From 4c40daa3a143f34fcff7ce941609d7a9d833512c Mon Sep 17 00:00:00 2001 From: cytopia Date: Thu, 3 May 2018 00:16:13 +0200 Subject: [PATCH 1/2] Add HTTPS support --- .travis.yml | 4 +- Dockerfile | 113 ++-- README.md | 53 +- build/docker-attach.sh | 63 --- build/docker-build.sh | 30 +- build/docker-enter.sh | 55 -- build/docker-rebuild.sh | 30 +- build/docker-start.sh | 60 -- data/create-vhost.sh | 40 ++ data/docker-entrypoint.d/00-base-libs.sh | 103 ++++ data/docker-entrypoint.d/01-uid-gid.sh | 140 +++++ data/docker-entrypoint.d/02-timezone.sh | 38 ++ data/docker-entrypoint.d/03-docker-logs.sh | 37 ++ data/docker-entrypoint.d/04-php-fpm.sh | 98 ++++ 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 | 123 ++++ data/docker-entrypoint.d/08-cert-gen.sh | 102 ++++ .../docker-entrypoint.d/09-fix-permissions.sh | 42 ++ data/docker-entrypoint.d/10-supervisord.sh | 51 ++ data/docker-entrypoint.sh | 526 +++++------------- data/supervisord.conf | 26 - data/vhost-gen/main.yml | 11 +- data/vhost-gen/{conf.yml => mass.yml} | 11 +- 24 files changed, 1429 insertions(+), 706 deletions(-) delete mode 100755 build/docker-attach.sh delete mode 100755 build/docker-enter.sh delete mode 100755 build/docker-start.sh create mode 100755 data/create-vhost.sh create mode 100755 data/docker-entrypoint.d/00-base-libs.sh create mode 100755 data/docker-entrypoint.d/01-uid-gid.sh create mode 100755 data/docker-entrypoint.d/02-timezone.sh create mode 100755 data/docker-entrypoint.d/03-docker-logs.sh create mode 100755 data/docker-entrypoint.d/04-php-fpm.sh create mode 100755 data/docker-entrypoint.d/05-main-vhost.sh create mode 100755 data/docker-entrypoint.d/06-mass-vhost.sh create mode 100755 data/docker-entrypoint.d/07-vhost-gen.sh create mode 100755 data/docker-entrypoint.d/08-cert-gen.sh create mode 100755 data/docker-entrypoint.d/09-fix-permissions.sh create mode 100755 data/docker-entrypoint.d/10-supervisord.sh delete mode 100644 data/supervisord.conf rename data/vhost-gen/{conf.yml => mass.yml} (93%) diff --git a/.travis.yml b/.travis.yml index d2afc81..ca26eec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,7 +71,7 @@ jobs: elif [ "${TRAVIS_BRANCH}" == "master" ]; then docker build --no-cache=true -t "${IMAGE}:latest" . && docker images; - elif [[ ${TRAVIS_BRANCH} =~ ^(release[/-][.0-9]+)$ ]]; then + elif [[ ${TRAVIS_BRANCH} =~ ^(release-[.0-9]+)$ ]]; then docker build --no-cache=true -t "${IMAGE}:${TRAVIS_BRANCH}" . && docker images; else @@ -91,7 +91,7 @@ jobs: elif [ "${TRAVIS_BRANCH}" == "master" ]; then echo "Pushing ${IMAGE}:latest" && docker push "${IMAGE}:latest"; - elif [[ ${TRAVIS_BRANCH} =~ ^(release[/-][.0-9]+)$ ]]; then + elif [[ ${TRAVIS_BRANCH} =~ ^(release-[.0-9]+)$ ]]; then echo "Pushing ${IMAGE}:${TRAVIS_BRANCH}" && docker push "${IMAGE}:${TRAVIS_BRANCH}"; else diff --git a/Dockerfile b/Dockerfile index 9e52b80..6b51d0b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,14 +3,31 @@ MAINTAINER "cytopia" ### -### Labels +### Build arguments ### -LABEL \ - name="cytopia's Apache 2.2 Image" \ - image="apache-2.2" \ - vendor="devilbox" \ - license="MIT" \ - build-date="2017-10-01" +ARG VHOST_GEN_GIT_REF=0.5 +ARG CERT_GEN_GIT_REF=0.2 + +ENV BUILD_DEPS \ + autoconf \ + gcc \ + git \ + make \ + wget + +ENV RUN_DEPS \ + ca-certificates \ + python-yaml \ + supervisor + + +### +### Runtime arguments +### +ENV MY_USER=daemon +ENV MY_GROUP=daemon +ENV HTTPD_START="httpd-foreground" +ENV HTTPD_RELOAD="/usr/local/apache2/bin/httpd -k restart" ### @@ -22,17 +39,10 @@ RUN set -x \ && apt-get update \ && apt-get upgrade -y \ && apt-get install --no-install-recommends --no-install-suggests -y \ - autoconf \ - gcc \ - make \ - python-yaml \ - supervisor \ - wget \ - && rm -rf /var/lib/apt/lists/* \ - && apt-get purge -y --auto-remove - -# mod-proxy-fcgi -RUN set -x \ + ${BUILD_DEPS} \ + ${RUN_DEPS} \ + \ + # mod-proxy-fcgi && wget --no-check-certificate -O mod-proxy-fcgi.tar.gz https://github.com/devilbox/mod-proxy-fcgi/archive/master.tar.gz \ && tar xvfz mod-proxy-fcgi.tar.gz \ && cd mod-proxy-fcgi-master \ @@ -41,33 +51,30 @@ RUN set -x \ && make \ && make install \ && cd .. \ - && rm -rf mod-proxy-fcgi* - -# vhost-gen -RUN set -x \ - && wget --no-check-certificate -O vhost_gen.tar.gz https://github.com/devilbox/vhost-gen/archive/master.tar.gz \ - && tar xfvz vhost_gen.tar.gz \ - && cd vhost-gen-master \ + && rm -rf mod-proxy-fcgi* \ + \ + # Install vhost-gen + && git clone https://github.com/devilbox/vhost-gen \ + && cd vhost-gen \ + && git checkout "${VHOST_GEN_GIT_REF}" \ && make install \ && cd .. \ - && rm -rf vhost*gen* - -# watcherd -RUN set -x \ + && rm -rf vhost*gen* \ + \ + # Install cert-gen + && wget --no-check-certificate -O /usr/bin/ca-gen https://raw.githubusercontent.com/devilbox/cert-gen/${CERT_GEN_GIT_REF}/bin/ca-gen \ + && wget --no-check-certificate -O /usr/bin/cert-gen https://raw.githubusercontent.com/devilbox/cert-gen/${CERT_GEN_GIT_REF}/bin/cert-gen \ + && chmod +x /usr/bin/ca-gen \ + && chmod +x /usr/bin/cert-gen \ + \ + # Install watcherd && wget --no-check-certificate -O /usr/bin/watcherd https://raw.githubusercontent.com/devilbox/watcherd/master/watcherd \ - && chmod +x /usr/bin/watcherd - -# cleanup -RUN set -x \ - && apt-get update \ - && apt-get remove -y \ - autoconf \ - gcc \ - make \ - wget \ - && apt-get autoremove -y \ - && rm -rf /var/lib/apt/lists/* \ - && apt-get purge -y --auto-remove + && chmod +x /usr/bin/watcherd \ + \ + # Clean-up + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps \ + ${BUILD_DEPS} \ + && rm -rf /var/lib/apt/lists/* # Add custom config directive to httpd server RUN set -x \ @@ -79,6 +86,19 @@ RUN set -x \ echo "Include /etc/httpd-custom.d/*.conf"; \ echo "Include /etc/httpd/conf.d/*.conf"; \ echo "Include /etc/httpd/vhost.d/*.conf"; \ + \ + #echo "LoadModule ssl_module modules/mod_ssl.so"; \ + echo "Listen 443"; \ + echo "NameVirtualHost *:443"; \ + echo "SSLCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES"; \ + echo "SSLProxyCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES"; \ + echo "SSLHonorCipherOrder on"; \ + echo "SSLProtocol all -SSLv2 -SSLv3"; \ + echo "SSLProxyProtocol all -SSLv2 -SSLv3"; \ + echo "SSLPassPhraseDialog builtin"; \ + echo "SSLSessionCache \"shmcb:/usr/local/apache2/logs/ssl_scache(512000)\""; \ + echo "SSLSessionCacheTimeout 300"; \ + echo "SSLMutex \"file:/usr/local/apache2/logs/ssl_mutex\""; \ ) >> /usr/local/apache2/conf/httpd.conf # create directories @@ -89,15 +109,16 @@ RUN set -x \ && mkdir -p /var/www/default/htdocs \ && mkdir -p /shared/httpd \ && chmod 0775 /shared/httpd \ - && chown daemon:daemon /shared/httpd + && chown ${MY_USER}:${MY_GROUP} /shared/httpd ### ### Copy files ### -COPY ./data/vhost-gen/conf.yml /etc/vhost-gen/conf.yml COPY ./data/vhost-gen/main.yml /etc/vhost-gen/main.yml -COPY ./data/supervisord.conf /etc/supervisord.conf +COPY ./data/vhost-gen/mass.yml /etc/vhost-gen/mass.yml +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 @@ -105,12 +126,14 @@ COPY ./data/docker-entrypoint.sh /docker-entrypoint.sh ### Ports ### EXPOSE 80 +EXPOSE 443 ### ### Volumes ### VOLUME /shared/httpd +VOLUME /ca ### diff --git a/README.md b/README.md index 83ba58e..556ad05 100644 --- a/README.md +++ b/README.md @@ -29,12 +29,16 @@ Find me on **[Docker Hub](https://hub.docker.com/r/devilbox/apache-2.2)**: 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=.local` +3. You can optionally specify a global server name suffix via e.g.: `-e MASS_VHOST_TLD=.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` -4. Allow the Docker to expose its port via `-p 80:80`. -5. Have DNS names point to the IP address the docker runs on (e.g. via `/etc/hosts`) +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`) -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=.local`, afterwards your above created vhost would be reachable via `http://mydir.local`. +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 +`http://mydir.loc`. Just to give you a few examples: @@ -67,7 +71,7 @@ docker run -it \ -p 80:80 \ -e MASS_VHOST_ENABLE=1 \ -e MASS_VHOST_DOCROOT=www \ - -e MASS_VHOST_TLD=.local \ + -e MASS_VHOST_TLD=.loc \ -v /local/path:/shared/httpd \ devilbox/apache-2.2 ``` @@ -99,7 +103,7 @@ PHP-FPM is not included inside this Docker container, but can be enabled to cont #### Disabling the default virtual host -If you only want to server you custom projects and don't need the default virtual host, you can disable it by `-e MAIN_VHOST_DISABLE=1`. +If you only want to server you custom projects and don't need the default virtual host, you can disable it by `-e MAIN_VHOST_ENABLE=0`. ## Options @@ -130,7 +134,10 @@ This Docker container adds a lot of injectables in order to customize it to your | Variable | Type | Default | Description | |----------|------|---------|-------------| -| MAIN_VHOST_DISABLE | bool | `0` | By default there is a standard (catch-all) vhost configured to accept requests served from `/var/www/default/htdocs`. If you want to disable it, set the value to `1`.
Note:The `htdocs` dir name can be changed with `MAIN_VHOST_DOCROOT`. See below. | +| MAIN_VHOST_ENABLE | bool | `1` | By default there is a standard (catch-all) vhost configured to accept requests served from `/var/www/default/htdocs`. If you want to disable it, set the value to `0`.
Note:The `htdocs` dir name can be changed with `MAIN_VHOST_DOCROOT`. See below. | +| MAIN_VHOST_SSL_TYPE | string | `plain` | | +| MAIN_VHOST_SSL_GEN | bool | `0` | `0`: Do not generate an ssl certificate
`1`: Generate self-signed certificate automatically | +| MAIN_VHOST_SSL_CN | string | `localhost` | Comma separated list of CN names for SSL certificate generation (The domain names by which you want to reach the default server) | | MAIN_VHOST_DOCROOT | string | `htdocs`| This is the directory name appended to `/var/www/default/` from which the default virtual host will serve its files.
Default:
`/var/www/default/htdocs`
Example:
`MAIN_VHOST_DOCROOT=www`
Doc root: `/var/www/default/www` | | MAIN_VHOST_TPL | string | `cfg` | Directory within th default vhost base path (`/var/www/default`) 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.
Resulting default path:
`/var/www/default/cfg` | | MAIN_VHOST_STATUS_ENABLE | bool | `0` | Enable httpd status page. | @@ -141,7 +148,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_TLD | string | `.local`| 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:`.local`
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_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_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/` | @@ -159,7 +168,8 @@ This Docker container adds a lot of injectables in order to customize it to your | Docker | Description | |--------|-------------| -| 80 | Apache listening Port | +| 80 | HTTP listening Port | +| 443 | HTTPS listening Port | ## Examples @@ -248,8 +258,31 @@ It allows any of the following combinations: ``` Server version: Apache/2.2.34 (Unix) -Server built: Sep 19 2017 01:07:59 +Server built: Jan 18 2018 23:12:10 Server's Module Magic Number: 20051115:43 Server loaded: APR 1.5.1, APR-Util 1.5.4 +Compiled using: APR 1.5.1, APR-Util 1.5.4 +Architecture: 64-bit Server MPM: Prefork + threaded: no + forked: yes (variable process count) +Server compiled with.... + -D APACHE_MPM_DIR="server/mpm/prefork" + -D APR_HAS_SENDFILE + -D APR_HAS_MMAP + -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) + -D APR_USE_SYSVSEM_SERIALIZE + -D APR_USE_PTHREAD_SERIALIZE + -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT + -D APR_HAS_OTHER_CHILD + -D AP_HAVE_RELIABLE_PIPED_LOGS + -D DYNAMIC_MODULE_LIMIT=128 + -D HTTPD_ROOT="/usr/local/apache2" + -D SUEXEC_BIN="/usr/local/apache2/bin/suexec" + -D DEFAULT_PIDLOG="logs/httpd.pid" + -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" + -D DEFAULT_LOCKFILE="logs/accept.lock" + -D DEFAULT_ERRORLOG="logs/error_log" + -D AP_TYPES_CONFIG_FILE="conf/mime.types" + -D SERVER_CONFIG_FILE="conf/httpd.conf" ``` diff --git a/build/docker-attach.sh b/build/docker-attach.sh deleted file mode 100755 index b020098..0000000 --- a/build/docker-attach.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh -eu - - -### -### Globals -### -CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)/.." - - -### -### Funcs -### -run() { - _cmd="${1}" - _red="\033[0;31m" - _green="\033[0;32m" - _reset="\033[0m" - _user="$(whoami)" - - printf "${_red}%s \$ ${_green}${_cmd}${_reset}\n" "${_user}" - sh -c "LANG=C LC_ALL=C ${_cmd}" -} - - -### -### Checks -### - -# Check Dockerfile -if [ ! -f "${CWD}/Dockerfile" ]; then - echo "Dockerfile not found in: ${CWD}/Dockerfile." - exit 1 -fi - -# Test Docker name -if ! grep -q 'image=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'image' LABEL found" - exit -fi - -# Test Docker vendor -if ! grep -q 'vendor=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'vendor' LABEL found" - exit -fi - -# Retrieve values -NAME="$( grep 'image=".*"' "${CWD}/Dockerfile" | sed 's/^[[:space:]]*//g' | awk -F'"' '{print $2}' )" -VEND="$( grep -Eo 'vendor="(.*)"' "${CWD}/Dockerfile" | awk -F'"' '{print $2}' )" -COUNT="$( docker ps | grep -c "${VEND}/${NAME}" || true)" -if [ "${COUNT}" != "1" ]; then - echo "${COUNT} '${VEND}/${NAME}' container running. Unable to attach." - exit 1 -fi - - -### -### Attach -### -DID="$(docker ps | grep "${VEND}/${NAME}" | awk '{print $1}')" - -echo "Attaching to: ${VEND}/${NAME}" -run "docker exec -it ${DID} env TERM=xterm /bin/bash -l" diff --git a/build/docker-build.sh b/build/docker-build.sh index a5ed846..a336e47 100755 --- a/build/docker-build.sh +++ b/build/docker-build.sh @@ -5,7 +5,8 @@ ### Globals ### CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)/.." - +VEND=devilbox +NAME=apache-2.2 ### ### Funcs @@ -32,23 +33,6 @@ if [ ! -f "${CWD}/Dockerfile" ]; then exit 1 fi -# Test Docker name -if ! grep -q 'image=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'image' LABEL found" - exit -fi - -# Test Docker vendor -if ! grep -q 'vendor=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'vendor' LABEL found" - exit -fi - -# Retrieve values -NAME="$( grep 'image=".*"' "${CWD}/Dockerfile" | sed 's/^[[:space:]]*//g' | awk -F'"' '{print $2}' )" -VEND="$( grep -Eo 'vendor="(.*)"' "${CWD}/Dockerfile" | awk -F'"' '{print $2}' )" -DATE="$( date '+%Y-%m-%d' )" - ### ### Update Base @@ -61,9 +45,6 @@ run "docker pull ${MY_BASE}" ### Build ### -# Update build date -run "sed -i'' 's/build-date=\".*\"/build-date=\"${DATE}\"/g' ${CWD}/Dockerfile" - # Build Docker run "docker build -t ${VEND}/${NAME} ${CWD}" @@ -71,11 +52,10 @@ run "docker build -t ${VEND}/${NAME} ${CWD}" ### ### Retrieve information afterwards and Update README.md ### -docker run -d --rm --name my_tmp_${NAME} -t ${VEND}/${NAME} -INFO="$( docker exec my_tmp_${NAME} httpd -V | grep -E '^Server.*(version|built|Module|loaded|MPM)' )" -docker stop "$(docker ps | grep "my_tmp_${NAME}" | awk '{print $1}')" > /dev/null +DID="$( docker run -d --rm -t ${VEND}/${NAME} )" +INFO="$( docker exec "${DID}" httpd -V 2>&1 )" +docker stop "${DID}" -INFO="$( echo "${INFO}" | sed 's/\s$//g' )" # remove trailing space echo "${INFO}" sed -i'' '/##[[:space:]]Version/q' "${CWD}/README.md" diff --git a/build/docker-enter.sh b/build/docker-enter.sh deleted file mode 100755 index 841d638..0000000 --- a/build/docker-enter.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh -eu - - -### -### Globals -### -CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)/.." - - -### -### Funcs -### -run() { - _cmd="${1}" - _red="\033[0;31m" - _green="\033[0;32m" - _reset="\033[0m" - _user="$(whoami)" - - printf "${_red}%s \$ ${_green}${_cmd}${_reset}\n" "${_user}" - sh -c "LANG=C LC_ALL=C ${_cmd}" -} - - -### -### Checks -### - -# Check Dockerfile -if [ ! -f "${CWD}/Dockerfile" ]; then - echo "Dockerfile not found in: ${CWD}/Dockerfile." - exit 1 -fi - -# Test Docker name -if ! grep -q 'image=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'image' LABEL found" - exit -fi - -# Test Docker vendor -if ! grep -q 'vendor=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'vendor' LABEL found" - exit -fi - -# Retrieve values -NAME="$( grep 'image=".*"' "${CWD}/Dockerfile" | sed 's/^[[:space:]]*//g' | awk -F'"' '{print $2}' )" -VEND="$( grep -Eo 'vendor="(.*)"' "${CWD}/Dockerfile" | awk -F'"' '{print $2}' )" - - -### -### Enter -### -run "docker run -i --entrypoint /bin/bash -t ${VEND}/${NAME}" diff --git a/build/docker-rebuild.sh b/build/docker-rebuild.sh index 2919859..ac45681 100755 --- a/build/docker-rebuild.sh +++ b/build/docker-rebuild.sh @@ -5,7 +5,8 @@ ### Globals ### CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)/.." - +VEND=devilbox +NAME=apache-2.2 ### ### Funcs @@ -32,23 +33,6 @@ if [ ! -f "${CWD}/Dockerfile" ]; then exit 1 fi -# Test Docker name -if ! grep -q 'image=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'image' LABEL found" - exit -fi - -# Test Docker vendor -if ! grep -q 'vendor=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'vendor' LABEL found" - exit -fi - -# Retrieve values -NAME="$( grep 'image=".*"' "${CWD}/Dockerfile" | sed 's/^[[:space:]]*//g' | awk -F'"' '{print $2}' )" -VEND="$( grep -Eo 'vendor="(.*)"' "${CWD}/Dockerfile" | awk -F'"' '{print $2}' )" -DATE="$( date '+%Y-%m-%d' )" - ### ### Update Base @@ -61,9 +45,6 @@ run "docker pull ${MY_BASE}" ### Build ### -# Update build date -run "sed -i'' 's/build-date=\".*\"/build-date=\"${DATE}\"/g' ${CWD}/Dockerfile" - # Build Docker run "docker build --no-cache -t ${VEND}/${NAME} ${CWD}" @@ -71,11 +52,10 @@ run "docker build --no-cache -t ${VEND}/${NAME} ${CWD}" ### ### Retrieve information afterwards and Update README.md ### -docker run -d --rm --name my_tmp_${NAME} -t ${VEND}/${NAME} -INFO="$( docker exec my_tmp_${NAME} httpd -V | grep -E '^Server.*(version|built|Module|loaded|MPM)' )" -docker stop "$(docker ps | grep "my_tmp_${NAME}" | awk '{print $1}')" > /dev/null +DID="$( docker run -d --rm -t ${VEND}/${NAME} )" +INFO="$( docker exec "${DID}" httpd -V 2>&1 )" +docker stop "${DID}" -INFO="$( echo "${INFO}" | sed 's/\s$//g' )" # remove trailing space echo "${INFO}" sed -i'' '/##[[:space:]]Version/q' "${CWD}/README.md" diff --git a/build/docker-start.sh b/build/docker-start.sh deleted file mode 100755 index b89c00d..0000000 --- a/build/docker-start.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh -eu - - -### -### Globals -### -CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)/.." - - -### -### Funcs -### -run() { - _cmd="${1}" - _red="\033[0;31m" - _green="\033[0;32m" - _reset="\033[0m" - _user="$(whoami)" - - printf "${_red}%s \$ ${_green}${_cmd}${_reset}\n" "${_user}" - sh -c "LANG=C LC_ALL=C ${_cmd}" -} - - -### -### Checks -### - -# Check Dockerfile -if [ ! -f "${CWD}/Dockerfile" ]; then - echo "Dockerfile not found in: ${CWD}/Dockerfile." - exit 1 -fi - - -# Test Docker name -if ! grep -q 'image=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'image' LABEL found" - exit -fi - -# Test Docker vendor -if ! grep -q 'vendor=".*"' "${CWD}/Dockerfile" > /dev/null 2>&1; then - echo "No 'vendor' LABEL found" - exit -fi - -# Retrieve values -NAME="$( grep 'image=".*"' "${CWD}/Dockerfile" | sed 's/^[[:space:]]*//g' | awk -F'"' '{print $2}' )" -VEND="$( grep -Eo 'vendor="(.*)"' "${CWD}/Dockerfile" | awk -F'"' '{print $2}' )" - - -### -### Run -### -_args="" -if [ "${#}" != "0" ]; then - _args="${*}" -fi -run "docker run -it ${_args} ${VEND}/${NAME}" diff --git a/data/create-vhost.sh b/data/create-vhost.sh new file mode 100755 index 0000000..24faa3c --- /dev/null +++ b/data/create-vhost.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +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}" +VERBOSE="${7}" +GENERATE_SSL="${8}" + +if [ "${GENERATE_SSL}" = "1" ]; then + if [ ! -d "/etc/httpd/cert/mass" ]; then + mkdir -p "/etc/httpd/cert/mass" + fi + _email="admin@${VHOST_NAME}${VHOST_TLD}" + _domain="${VHOST_NAME}${VHOST_TLD}" + _domains="*.${VHOST_NAME}${VHOST_TLD}" + _out_key="/etc/httpd/cert/mass/${VHOST_NAME}${VHOST_TLD}.key" + _out_csr="/etc/httpd/cert/mass/${VHOST_NAME}${VHOST_TLD}.csr" + _out_crt="/etc/httpd/cert/mass/${VHOST_NAME}${VHOST_TLD}.crt" + if ! cert-gen -v -c DE -s Berlin -l Berlin -o Devilbox -u Devilbox -n "${_domain}" -e "${_email}" -a "${_domains}" "${CA_KEY}" "${CA_CRT}" "${_out_key}" "${_out_csr}" "${_out_crt}"; then + echo "[FAILED] Failed to add SSL certificate for ${VHOST_NAME}${VHOST_TLD}" + exit 1 + fi +fi + +cmd="vhost_gen.py -p \"${VHOST_PATH}\" -n \"${VHOST_NAME}\" -c /etc/vhost-gen/mass.yml -o \"${VHOST_TPL}\" -s ${VERBOSE} -m both" +if [ -n "${VERBOSE}" ]; then + echo "\$ ${cmd}" +fi + +if ! eval "${cmd}"; then + echo "[FAILED] Failed to add vhost for ${VHOST_NAME}${VHOST_TLD}" + exit 1 +fi diff --git a/data/docker-entrypoint.d/00-base-libs.sh b/data/docker-entrypoint.d/00-base-libs.sh new file mode 100755 index 0000000..361ae34 --- /dev/null +++ b/data/docker-entrypoint.d/00-base-libs.sh @@ -0,0 +1,103 @@ +#!/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/data/docker-entrypoint.d/01-uid-gid.sh b/data/docker-entrypoint.d/01-uid-gid.sh new file mode 100755 index 0000000..b405297 --- /dev/null +++ b/data/docker-entrypoint.d/01-uid-gid.sh @@ -0,0 +1,140 @@ +#!/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}" + if [ -d "${homedir}" ]; then + run "chown -R ${username} ${homedir}" "${debug}" + fi + 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}" + if [ -d "${homedir}" ]; then + run "chown -R :${groupname} ${homedir}" "${debug}" + fi + 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/data/docker-entrypoint.d/02-timezone.sh b/data/docker-entrypoint.d/02-timezone.sh new file mode 100755 index 0000000..19b31c0 --- /dev/null +++ b/data/docker-entrypoint.d/02-timezone.sh @@ -0,0 +1,38 @@ +#!/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/data/docker-entrypoint.d/03-docker-logs.sh b/data/docker-entrypoint.d/03-docker-logs.sh new file mode 100755 index 0000000..408832f --- /dev/null +++ b/data/docker-entrypoint.d/03-docker-logs.sh @@ -0,0 +1,37 @@ +#!/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/data/docker-entrypoint.d/04-php-fpm.sh b/data/docker-entrypoint.d/04-php-fpm.sh new file mode 100755 index 0000000..ca433fa --- /dev/null +++ b/data/docker-entrypoint.d/04-php-fpm.sh @@ -0,0 +1,98 @@ +#!/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}" +} diff --git a/data/docker-entrypoint.d/05-main-vhost.sh b/data/docker-entrypoint.d/05-main-vhost.sh new file mode 100755 index 0000000..a6d27b0 --- /dev/null +++ b/data/docker-entrypoint.d/05-main-vhost.sh @@ -0,0 +1,214 @@ +#!/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/data/docker-entrypoint.d/06-mass-vhost.sh b/data/docker-entrypoint.d/06-mass-vhost.sh new file mode 100755 index 0000000..0c52504 --- /dev/null +++ b/data/docker-entrypoint.d/06-mass-vhost.sh @@ -0,0 +1,165 @@ +#!/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/data/docker-entrypoint.d/07-vhost-gen.sh b/data/docker-entrypoint.d/07-vhost-gen.sh new file mode 100755 index 0000000..e75516f --- /dev/null +++ b/data/docker-entrypoint.d/07-vhost-gen.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + + +############################################################ +# Functions +############################################################ + +### +### Set PHP_FPM +### +vhost_gen_php_fpm() { + local enable="${1}" + local addr="${2}" + local port="${3}" + local config="${4}" + local debug="${5}" + + 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}" + 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 + run "vhost_gen.py -n localhost -p ${docroot} -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 +} diff --git a/data/docker-entrypoint.d/08-cert-gen.sh b/data/docker-entrypoint.d/08-cert-gen.sh new file mode 100755 index 0000000..845091c --- /dev/null +++ b/data/docker-entrypoint.d/08-cert-gen.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + + +############################################################ +# Functions +############################################################ + +### +### Generate CA +### +cert_gen_generate_ca() { + local key="${1}" + local crt="${2}" + local verbose="${3}" + local debug="${4}" + + # Create directories + if [ ! -d "$( dirname "${key}" )" ]; then + run "mkdir -p $( dirname ${key} )" "${debug}" + fi + if [ ! -d "$( dirname "${crt}" )" ]; then + run "mkdir -p $( dirname ${crt} )" "${debug}" + fi + + # cert-gen verbosity + if [ "${verbose}" -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}" + fi +} + + +### +### Generate SSL certificate +### +cert_gen_generate_cert() { + local enable="${1}" + local ssl_type="${2}" + local ca_key="${3}" + local ca_crt="${4}" + local key="${5}" + local csr="${6}" + local crt="${7}" + local domains="${8}" + local verbose="${9}" + local debug="${10}" + + # If not enabled, skip SSL certificate eneration + if [ "${enable}" != "1" ]; then + return + fi + + # If no SSL is requested, skip the SSL certificate generation + if [ "${ssl_type}" = "plain" ]; then + return + fi + + # Create directories + if [ ! -d "$( dirname "${key}" )" ]; then + run "mkdir -p $( dirname ${key} )" "${debug}" + fi + if [ ! -d "$( dirname "${csr}" )" ]; then + run "mkdir -p $( dirname ${csr} )" "${debug}" + fi + if [ ! -d "$( dirname "${crt}" )" ]; then + run "mkdir -p $( dirname ${crt} )" "${debug}" + fi + + # cert-gen verbosity + if [ "${verbose}" -gt "0" ]; then + verbose="-v" + else + verbose="" + fi + + # Get domain name and alt_names + cn= + alt_names= + for domain in ${domains//,/ }; do + domain="$( echo "${domain}" | xargs )" # trim + + # First domain goes into CN + if [ -z "${cn}" ]; then + cn="${domain}" + fi + # Create space separated list + alt_names=" ${alt_names} ${domain}" + 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}" +} diff --git a/data/docker-entrypoint.d/09-fix-permissions.sh b/data/docker-entrypoint.d/09-fix-permissions.sh new file mode 100755 index 0000000..b2772da --- /dev/null +++ b/data/docker-entrypoint.d/09-fix-permissions.sh @@ -0,0 +1,42 @@ +#!/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/data/docker-entrypoint.d/10-supervisord.sh b/data/docker-entrypoint.d/10-supervisord.sh new file mode 100755 index 0000000..6f1d9c1 --- /dev/null +++ b/data/docker-entrypoint.d/10-supervisord.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + + +############################################################ +# Functions +############################################################ + + +### +### Create supervisord.conf +### +supervisord_create() { + local httpd_command="${1}" + local watcherd_command="${2}" + local config="${3}" + + if [ -d "$( basename "${config}" )" ]; then + mkdir -p "$( basename "${config}" )" + fi + + { + echo "[supervisord]" + echo "user=root" + echo "nodaemon=true" + echo + echo "[program:httpd]" + echo "command=${httpd_command}" + echo "autostart=true" + echo "autorestart=true" + echo "stdout_logfile=/dev/stdout" + echo "stdout_logfile_maxbytes=0" + echo "stderr_logfile=/dev/stderr" + echo "stderr_logfile_maxbytes=0" + echo "stdout_events_enabled=true" + echo "stderr_events_enabled=true" + echo + echo "[program:watcherd]" + echo "command=${watcherd_command}" + echo "autorestart=false" + echo "stdout_logfile=/dev/stdout" + echo "stdout_logfile_maxbytes=0" + echo "stderr_logfile=/dev/stderr" + echo "stderr_logfile_maxbytes=0" + echo "stdout_events_enabled=true" + echo "stderr_events_enabled=true" + } > "${config}" +} diff --git a/data/docker-entrypoint.sh b/data/docker-entrypoint.sh index 3ded9c0..cece499 100755 --- a/data/docker-entrypoint.sh +++ b/data/docker-entrypoint.sh @@ -4,473 +4,202 @@ set -e set -u set -o pipefail - - -################################################################################ -# VARIABLES -################################################################################ - -MY_USER="daemon" -MY_GROUP="daemon" -DEBUG_COMMANDS=0 - ### -### Defaults +### Globals ### +# Set via Dockerfile +# MY_USER +# MY_GROUP +# HTTPD_START +# HTTPD_RELOAD -################################################################################ -# FUNCTIONS -################################################################################ - -run() { - _cmd="${1}" - _debug="0" - - _red="\033[0;31m" - _green="\033[0;32m" - _reset="\033[0m" - _user="$(whoami)" - - - # If 2nd argument is set and enabled, allow debug command - if [ "${#}" = "2" ]; then - _debug="${2}" - fi - - if [ "${DEBUG_COMMANDS}" -gt "1" ] || [ "${_debug}" -gt "1" ]; then - printf "${_red}%s \$ ${_green}${_cmd}${_reset}\n" "${_user}" - fi - sh -c "LANG=C LC_ALL=C ${_cmd}" -} - -log() { - _lvl="${1}" - _msg="${2}" - - _clr_ok="\033[0;32m" - _clr_info="\033[0;34m" - _clr_warn="\033[0;33m" - _clr_err="\033[0;31m" - _clr_rst="\033[0m" - - if [ "${_lvl}" = "ok" ]; then - printf "${_clr_ok}[OK] %s${_clr_rst}\n" "${_msg}" - elif [ "${_lvl}" = "info" ]; then - printf "${_clr_info}[INFO] %s${_clr_rst}\n" "${_msg}" - elif [ "${_lvl}" = "warn" ]; then - printf "${_clr_warn}[WARN] %s${_clr_rst}\n" "${_msg}" 1>&2 # stdout -> stderr - elif [ "${_lvl}" = "err" ]; then - printf "${_clr_err}[ERR] %s${_clr_rst}\n" "${_msg}" 1>&2 # stdout -> stderr - else - printf "${_clr_err}[???] %s${_clr_rst}\n" "${_msg}" 1>&2 # stdout -> stderr - fi -} - -# Test if argument is an integer. -# -# @param mixed -# @return integer 0: is int | 1: not an int -isint() { - echo "${1}" | grep -Eq '^([0-9]|[1-9][0-9]*)$' -} +# 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" -################################################################################ -# SETTING INJECTABLES -################################################################################ ### -### Debug Mode Entrypoint? +### Source libs ### -if set | grep '^DEBUG_ENTRYPOINT=' >/dev/null 2>&1; then - if [ "${DEBUG_ENTRYPOINT}" = "1" ]; then - DEBUG_COMMANDS=1 - elif [ "${DEBUG_ENTRYPOINT}" = "2" ]; then - DEBUG_COMMANDS=2 - else - log "err" "Wrong value for \$DEBUG_ENTRYPOINT: '${DEBUG_ENTRYPOINT}'" - log "err" "Allowed values: 0, 1 and 2" - exit 1 - fi -fi +init="$( find "${CONFIG_DIR}" -name '*.sh' -type f | sort -u )" +for f in ${init}; do + # shellcheck disable=SC1090 + . "${f}" +done -### -### Debug Mode Runtime? -### -_RUNTIME_DEBUG_RUNTIME="0" -if set | grep '^DEBUG_RUNTIME=' >/dev/null 2>&1; then - if [ "${DEBUG_RUNTIME}" = "1" ]; then - _RUNTIME_DEBUG_RUNTIME="1" - fi -fi +############################################################# +## Basic Settings +############################################################# ### -### Use docker logs? +### Set Debug level ### -_RUNTIME_DOCKER_LOGS="0" -if ! set | grep '^DOCKER_LOGS=' >/dev/null 2>&1; then - log "info" "\$DOCKER_LOGS not set. Logging errors and access to log files inside container." -else - if [ "${DOCKER_LOGS}" = "1" ]; then - log "info" "\$DOCKER_LOGS enabled. Redirecting errors and access to Docker log (stderr and stdout)." - _RUNTIME_DOCKER_LOGS="1" - elif [ "${DOCKER_LOGS}" = "0" ]; then - log "info" "\$DOCKER_LOGS explicitly disabled. Logging errors and access to log files inside container." - else - log "err" "Invalid value for \$DOCKER_LOGS: ${DOCKER_LOGS}" - log "err" "Must be '1' (for On) or '0' (for Off)" - exit 1 - fi -fi +DEBUG_LEVEL="$( env_get "DEBUG_ENTRYPOINT" "0" )" +log "info" "Debug level: ${DEBUG_LEVEL}" "${DEBUG_LEVEL}" - -### -### Timezone -### -if ! set | grep '^TIMEZONE=' >/dev/null 2>&1; then - log "info" "\$TIMEZONE not set." -else - if [ -f "/usr/share/zoneinfo/${TIMEZONE}" ]; then - # Unix Time - log "info" "Setting docker timezone to: ${TIMEZONE}" - run "ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime" - else - log "err" "Invalid timezone for \$TIMEZONE." - log "err" "\$TIMEZONE: '${TIMEZONE}' does not exist." - exit 1 - fi -fi -log "info" "Docker date set to: $(date)" +DEBUG_RUNTIME="$( env_get "DEBUG_RUNTIME" "0" )" +log "info" "Runtime debug: ${DEBUG_RUNTIME}" "${DEBUG_LEVEL}" ### -### Change UID +### Change uid/gid ### -if ! set | grep '^NEW_UID=' >/dev/null 2>&1; then - log "info" "\$NEW_UID not set. Keeping default uid of '${MY_USER}'." -else - if ! isint "${NEW_UID}"; then - log "err" "\$NEW_UID is not an integer: '${NEW_UID}'" - exit 1 - else - if _user_line="$( getent passwd "${NEW_UID}" )"; then - _user_name="${_user_line%%:*}" - if [ "${_user_name}" != "${MY_USER}" ]; then - log "warn" "User with ${NEW_UID} already exists: ${_user_name}" - log "info" "Changing UID of ${_user_name} to 9999" - run "usermod -u 9999 ${_user_name}" - fi - fi - log "info" "Changing user '${MY_USER}' uid to: ${NEW_UID}" - run "usermod -u ${NEW_UID} ${MY_USER}" - fi -fi +set_uid "NEW_UID" "${MY_USER}" "${DEBUG_LEVEL}" +set_gid "NEW_GID" "${MY_GROUP}" "${DEBUG_LEVEL}" ### -### Change GID +### Set timezone ### -if ! set | grep '^NEW_GID=' >/dev/null 2>&1; then - log "info" "\$NEW_GID not set. Keeping default gid of '${MY_GROUP}'." -else - if ! isint "${NEW_GID}"; then - log "err" "\$NEW_GID is not an integer: '${NEW_GID}'" - exit 1 - else - if _group_line="$( getent group "${NEW_GID}" )"; then - _group_name="${_group_line%%:*}" - if [ "${_group_name}" != "${MY_GROUP}" ]; then - log "warn" "Group with ${NEW_GID} already exists: ${_group_name}" - log "info" "Changing GID of ${_group_name} to 9999" - run "groupmod -g 9999 ${_group_name}" - fi - fi - log "info" "Changing group '${MY_GROUP}' gid to: ${NEW_GID}" - run "groupmod -g ${NEW_GID} ${MY_GROUP}" - fi -fi +set_timezone "TIMEZONE" "${DEBUG_LEVEL}" -################################################################################ -# MAIN VHOST INJECTABLES -################################################################################ +############################################################# +## Variable exports +############################################################# ### -### Disable default vhost? +### Ensure Docker_LOGS is exported ### -_RUNTIME_MAIN_VHOST_ENABLE=1 -if ! set | grep '^MAIN_VHOST_DISABLE=' >/dev/null 2>&1; then - log "info" "\$MAIN_VHOST_DISABLE not set. Not disabling the default vhost." -else - if [ "${MAIN_VHOST_DISABLE}" = "0" ]; then - log "info" "\$MAIN_VHOST_DISABLE set to 0. Not disabling the default vhost." - elif [ "${MAIN_VHOST_DISABLE}" = "1" ]; then - log "info" "\$MAIN_VHOST_DISABLE set to 1. Disabling the default vhost." - _RUNTIME_MAIN_VHOST_ENABLE=0 - else - log "err" "\$MAIN_VHOST_DISABLE is set to ${MAIN_VHOST_DISABLE}, but must be 0 or 1." - exit 1 - fi -fi +export_docker_logs "DOCKER_LOGS" "${DEBUG_LEVEL}" ### -### Set main vhost document root sufix +### Ensure PHP-FPM variables are exported ### -_RUNTIME_MAIN_VHOST_DOCROOT="htdocs" -if ! set | grep '^MAIN_VHOST_DOCROOT=' >/dev/null 2>&1; then - log "info" "\$MAIN_VHOST_DOCROOT not specified. Keeping default: ${_RUNTIME_MAIN_VHOST_DOCROOT}" -else - log "info" "\$MAIN_VHOST_DOCROOT is set to: ${MAIN_VHOST_DOCROOT}" - _RUNTIME_MAIN_VHOST_DOCROOT="${MAIN_VHOST_DOCROOT}" -fi +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}" ### -### Set main vhost template directory +### Ensure MAIN_VHOST variables are exported ### -_RUNTIME_MAIN_VHOST_TPL="cfg" -if ! set | grep '^MAIN_VHOST_TPL=' >/dev/null 2>&1; then - log "info" "\$MAIN_VHOST_TPL not specified. Keeping default: ${_RUNTIME_MAIN_VHOST_TPL}" -else - log "info" "\$MAIN_VHOST_TPL is set to: ${_RUNTIME_MAIN_VHOST_TPL}" - _RUNTIME_MAIN_VHOST_TPL="${MAIN_VHOST_TPL}" -fi +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}" ### -### Set main vhost status page +### Ensure MASS_VHOST variables are exported ### -_RUNTIME_MAIN_VHOST_STATUS_ENABLE=0 -if ! set | grep '^MAIN_VHOST_STATUS_ENABLE=' >/dev/null 2>&1; then - log "info" "\$MAIN_VHOST_STATUS_ENABLE not specified. Disabling httpd status." -else - if [ "${MAIN_VHOST_STATUS_ENABLE}" = "0" ]; then - log "info" "\$MAIN_VHOST_STATUS_ENABLE set to 0. Disabling httpd status." - elif [ "${MAIN_VHOST_STATUS_ENABLE}" = "1" ]; then - log "info" "\$MAIN_VHOST_STATUS_ENABLE set to 1. Enabling httpd status." - _RUNTIME_MAIN_VHOST_STATUS_ENABLE="${MAIN_VHOST_STATUS_ENABLE}" - else - log "err" "\$MAIN_VHOST_STATUS_ENABLE is set to ${MAIN_VHOST_STATUS_ENABLE}, but must be 0 or 1." - exit 1 - fi -fi - -if [ "${_RUNTIME_MAIN_VHOST_STATUS_ENABLE}" -eq "1" ]; then - _RUNTIME_MAIN_VHOST_STATUS_ALIAS="/httpd-status" - if ! set | grep '^MAIN_VHOST_STATUS_ALIAS=' >/dev/null 2>&1; then - log "info" "\$MAIN_VHOST_STATUS_ALIAS not specified. Keeping default: ${_RUNTIME_MAIN_VHOST_STATUS_ALIAS}." - else - log "info" "Setting httpd status page to: '${MAIN_VHOST_STATUS_ALIAS}'" - _RUNTIME_MAIN_VHOST_STATUS_ALIAS="${MAIN_VHOST_STATUS_ALIAS}" - fi -fi +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}" - -################################################################################ -# MASS VHOST INJECTABLES -################################################################################ - ### -### Enable mass vhosts? +### Default and/or mass vhost must be enabled (at least one of them) ### -_RUNTIME_MASS_VHOST_ENABLE=0 -if ! set | grep '^MASS_VHOST_ENABLE=' >/dev/null 2>&1; then - log "info" "\$MASS_VHOST_ENABLE not set. Disabbling mass vhosts." -else - if [ "${MASS_VHOST_ENABLE}" = "0" ]; then - log "info" "\$MASS_VHOST_ENABLE set to 0. Disabling mass vhosts." - elif [ "${MASS_VHOST_ENABLE}" = "1" ]; then - log "info" "\$MASS_VHOST_ENABLE set to 1. Enabling mass vhosts." - _RUNTIME_MASS_VHOST_ENABLE=1 - else - log "err" "\$MASS_VHOST_ENABLE is set to ${MASS_VHOST_ENABLE}, but must be 0 or 1." - exit 1 - fi +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 mass vhost TLD -### -_RUNTIME_MASS_VHOST_TLD=".local" -if ! set | grep '^MASS_VHOST_TLD=' >/dev/null 2>&1; then - log "info" "\$MASS_VHOST_TLD not set. Keeping default: ${_RUNTIME_MASS_VHOST_TLD}" -else - log "info" "\$MASS_VHOST_TLD set to: ${MASS_VHOST_TLD}" - _RUNTIME_MASS_VHOST_TLD="${MASS_VHOST_TLD}" -fi +############################################################# +## vhost-gen Configuration +############################################################# ### -### Set mass vhost document root sufix +### Enable and configure PHP-FPM ### -_RUNTIME_MASS_VHOST_DOCROOT="htdocs" -if ! set | grep '^MASS_VHOST_DOCROOT=' >/dev/null 2>&1; then - log "info" "\$MASS_VHOST_DOCROOT not specified. Keeping default: ${_RUNTIME_MASS_VHOST_DOCROOT}" -else - log "info" "\$MASS_VHOST_DOCROOT is set to: ${MASS_VHOST_DOCROOT}" - _RUNTIME_MASS_VHOST_DOCROOT="${MASS_VHOST_DOCROOT}" -fi +vhost_gen_php_fpm "${PHP_FPM_ENABLE}" "${PHP_FPM_SERVER_ADDR}" "${PHP_FPM_SERVER_PORT}" "/etc/vhost-gen/main.yml" "${DEBUG_LEVEL}" +vhost_gen_php_fpm "${PHP_FPM_ENABLE}" "${PHP_FPM_SERVER_ADDR}" "${PHP_FPM_SERVER_PORT}" "/etc/vhost-gen/mass.yml" "${DEBUG_LEVEL}" ### -### Set mass vhost template directory +### Configure Docker logs ### -_RUNTIME_MASS_VHOST_TPL="cfg" -if ! set | grep '^MASS_VHOST_TPL=' >/dev/null 2>&1; then - log "info" "\$MASS_VHOST_TPL not specified. Keeping default: ${_RUNTIME_MASS_VHOST_TPL}" -else - log "info" "\$MASS_VHOST_TPL is set to: ${_RUNTIME_MASS_VHOST_TPL}" - _RUNTIME_MASS_VHOST_TPL="${MASS_VHOST_TPL}" -fi +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}" - -################################################################################ -# SHARED VHOST INJECTABLES (MAIN & MASS) -################################################################################ - ### -### Enable PHP-FPM +### Main vhost settings ### -_RUNTIME_PHP_FPM_ENABLE=0 -if ! set | grep '^PHP_FPM_ENABLE=' >/dev/null 2>&1; then - log "info" "\$PHP_FPM_ENABLE not set. Not enabling PHP-FPM." -else - if [ "${PHP_FPM_ENABLE}" = "0" ]; then - log "info" "\$PHP_FPM_ENABLE set to 0. Not enabling PHP-FPM." - elif [ "${PHP_FPM_ENABLE}" = "1" ]; then - log "info" "\$PHP_FPM_ENABLE set to 1. Enabling PHP-FPM." - _RUNTIME_PHP_FPM_ENABLE=1 - - ### - ### PHP-FPM Addres - ### - # Check if PHP-FPM address is set - if ! set | grep '^PHP_FPM_SERVER_ADDR=' >/dev/null 2>&1; then - log "err" "PHP-FPM is enabled, but \$PHP_FPM_SERVER_ADDR not specified." - exit 1 - fi - # Check if PHP-FPM address is not empty - if [ -z "${PHP_FPM_SERVER_ADDR}" ]; then - log "err" "PHP-FPM enabled, but \$PHP_FPM_SERVER_ADDR is empty." - exit 1 - fi - log "info" "\$PHP_FPM_SERVER_ADDR is set to: ${PHP_FPM_SERVER_ADDR}" - - else - log "err" "\$PHP_FPM_ENABLE is set to ${PHP_FPM_ENABLE}, but must be 0 or 1." - exit 1 - fi -fi +vhost_gen_main_vhost_httpd_status \ + "${MAIN_VHOST_STATUS_ENABLE}" \ + "${MAIN_VHOST_STATUS_ALIAS}" \ + "/etc/vhost-gen/main.yml" \ + "${DEBUG_LEVEL}" + +vhost_gen_generate_main_vhost \ + "${MAIN_VHOST_ENABLE}" \ + "/var/www/default/${MAIN_VHOST_DOCROOT}" \ + "/etc/vhost-gen/main.yml" \ + "/var/www/default/${MAIN_VHOST_TPL}" \ + "${MAIN_VHOST_SSL_TYPE}" \ + "${DEBUG_RUNTIME}" \ + "${DEBUG_LEVEL}" ### -### PHP-FPM Port +### Mass vhost settings ### -_RUNTIME_PHP_FPM_SERVER_PORT="9000" -if ! set | grep '^PHP_FPM_SERVER_PORT=' >/dev/null 2>&1; then - log "info" "\$PHP_FPM_SERVER_PORT not specified. Keeping default: ${_RUNTIME_PHP_FPM_SERVER_PORT}" -else - # Check if PHP-FPM port is not empty - if [ -z "${PHP_FPM_SERVER_PORT}" ]; then - log "err" "\$PHP_FPM_SERVER_PORT specified, but is empty." - exit 1 - fi - # Check if PHP-FPM port is an integer - if ! isint "${PHP_FPM_SERVER_PORT}"; then - log "err" "\$PHP_FPM_SERVER_PORT is not a valid integer: ${PHP_FPM_SERVER_PORT}" - exit 1 - fi - # Check if PHP-FPM port is in port range - if [ "${PHP_FPM_SERVER_PORT}" -lt 1 ] || [ "${PHP_FPM_SERVER_PORT}" -gt 65535 ] ; then - log "err" "\$PHP_FPM_SERVER_PORT is not in a valid port range: ${PHP_FPM_SERVER_PORT}" - exit 1 - fi - log "info" "\$PHP_FPM_SERVER_PORT is set to: ${PHP_FPM_SERVER_PORT}" - _RUNTIME_PHP_FPM_SERVER_PORT="${_RUNTIME_PHP_FPM_SERVER_PORT}" -fi +vhost_gen_mass_vhost_docroot \ + "${MASS_VHOST_ENABLE}" \ + "${MASS_VHOST_DOCROOT}" \ + "/etc/vhost-gen/mass.yml" \ + "${DEBUG_LEVEL}" + +vhost_gen_mass_vhost_tld \ + "${MASS_VHOST_ENABLE}" \ + "${MASS_VHOST_TLD}" \ + "/etc/vhost-gen/mass.yml" \ + "${DEBUG_LEVEL}" ################################################################################ -# SETUP CONFIGURATION +# cert-getn Configuration ################################################################################ ### -### Default and/or mass vhost must be enabled (at least one of them) +### Create Certificate Signing request ### -if [ "${_RUNTIME_MAIN_VHOST_ENABLE}" -eq "0" ] && [ "${_RUNTIME_MASS_VHOST_ENABLE}" -eq "0" ]; then - log "err" "Default vhost and mass vhosts are disabled." - exit 1 -fi +cert_gen_generate_ca "${CA_KEY}" "${CA_CRT}" "${DEBUG_RUNTIME}" "${DEBUG_LEVEL}" ### -### vhost-gen +### Generate main vhost ssl certificate ### -if [ "${_RUNTIME_PHP_FPM_ENABLE}" -eq "1" ]; then - run "sed -i'' 's/__PHP_ENABLE__/yes/g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__PHP_ENABLE__/yes/g' /etc/vhost-gen/main.yml" - run "sed -i'' 's/__PHP_ADDR__/${PHP_FPM_SERVER_ADDR}/g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__PHP_ADDR__/${PHP_FPM_SERVER_ADDR}/g' /etc/vhost-gen/main.yml" - run "sed -i'' 's/__PHP_PORT__/${_RUNTIME_PHP_FPM_SERVER_PORT}/g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__PHP_PORT__/${_RUNTIME_PHP_FPM_SERVER_PORT}/g' /etc/vhost-gen/main.yml" -else - run "sed -i'' 's/__PHP_ENABLE__/no/g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__PHP_ENABLE__/no/g' /etc/vhost-gen/main.yml" -fi +cert_gen_generate_cert \ + "${MAIN_VHOST_ENABLE}" \ + "${MAIN_VHOST_SSL_TYPE}" \ + "${CA_KEY}" \ + "${CA_CRT}" \ + "/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}" -if [ "${_RUNTIME_DOCKER_LOGS}" -eq "1" ]; then - run "sed -i'' 's/__DOCKER_LOGS_ERROR__/yes/g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__DOCKER_LOGS_ERROR__/yes/g' /etc/vhost-gen/main.yml" - run "sed -i'' 's/__DOCKER_LOGS_ACCESS__/yes/g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__DOCKER_LOGS_ACCESS__/yes/g' /etc/vhost-gen/main.yml" -else - run "sed -i'' 's/__DOCKER_LOGS_ERROR__/no/g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__DOCKER_LOGS_ERROR__/no/g' /etc/vhost-gen/main.yml" - run "sed -i'' 's/__DOCKER_LOGS_ACCESS__/no/g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__DOCKER_LOGS_ACCESS__/no/g' /etc/vhost-gen/main.yml" -fi -### -### Main vhost -### -if [ "${_RUNTIME_MAIN_VHOST_ENABLE}" -eq "1" ]; then - - # Enable status page? - if [ "${_RUNTIME_MAIN_VHOST_STATUS_ENABLE}" -eq "1" ]; then - run "sed -i'' 's/__ENABLE_STATUS__/yes/g' /etc/vhost-gen/main.yml" - run "sed -i'' 's|__STATUS_ALIAS__|${_RUNTIME_MAIN_VHOST_STATUS_ALIAS}|g' /etc/vhost-gen/main.yml" - else - run "sed -i'' 's/__ENABLE_STATUS__/no/g' /etc/vhost-gen/main.yml" - fi +################################################################################ +# Fix directory permissions +################################################################################ - # Debug creation? - if [ "${DEBUG_COMMANDS}" -gt "0" ]; then - _verb="-v" - else - _verb="" - fi - run "vhost_gen.py -n localhost -p /var/www/default/${_RUNTIME_MAIN_VHOST_DOCROOT} -c /etc/vhost-gen/main.yml -o /var/www/default/${_RUNTIME_MAIN_VHOST_TPL} ${_verb} -d -s" -fi - - -### -### Mass vhost (watcher config setup) -### -if [ "${_RUNTIME_MASS_VHOST_ENABLE}" -eq "1" ]; then - run "sed -i'' 's|__DOCROOT_SUFFIX__|${_RUNTIME_MASS_VHOST_DOCROOT}|g' /etc/vhost-gen/conf.yml" - run "sed -i'' 's/__TLD__/${_RUNTIME_MASS_VHOST_TLD}/g' /etc/vhost-gen/conf.yml" -fi +fix_perm "NEW_UID" "NEW_GID" "/ca" "1" "${DEBUG_LEVEL}" @@ -481,15 +210,26 @@ fi ### ### Supervisor or plain ### -if [ "${_RUNTIME_MASS_VHOST_ENABLE}" -eq "1" ]; then - if [ "${_RUNTIME_DEBUG_RUNTIME}" -gt "0" ]; then - _verb="-v" - else - _verb="" +if [ "${MASS_VHOST_ENABLE}" -eq "1" ]; then + + verbose="" + if [ "${DEBUG_RUNTIME}" -gt "0" ]; then + verbose="-v" fi - run "sed -i'' 's|__MASS_VHOST_TPL__|${_RUNTIME_MASS_VHOST_TPL}|g' /etc/supervisord.conf" - run "sed -i'' 's/__VERBOSE__/${_verb}/g' /etc/supervisord.conf" + + # Create watcherd sub commands + watcherd_add="create-vhost.sh '%%p' '%%n' '${MASS_VHOST_TLD}' '%%p/${MASS_VHOST_TPL}/' '${CA_KEY}' '${CA_CRT}' '${verbose}' '1'" + watcherd_del="rm /etc/httpd/vhost.d/%%n.conf" + watcherd_tri="${HTTPD_RELOAD}" + + supervisord_create \ + "${HTTPD_START}" \ + "watcherd -v -p /shared/httpd -a \"${watcherd_add}\" -d \"${watcherd_del}\" -t \"${watcherd_tri}\"" \ + "/etc/supervisord.conf" + + log "info" "Starting supervisord: $(supervisord -v)" "${DEBUG_LEVEL}" exec /usr/bin/supervisord -c /etc/supervisord.conf else - exec httpd-foreground + log "info" "Starting webserver" "${DEBUG_LEVEL}" + exec ${HTTPD_START} fi diff --git a/data/supervisord.conf b/data/supervisord.conf deleted file mode 100644 index 2266b1d..0000000 --- a/data/supervisord.conf +++ /dev/null @@ -1,26 +0,0 @@ -[supervisord] -user=root -nodaemon=true - -[program:apache] -command=httpd-foreground -autostart=true -autorestart=true -stdout_logfile=/dev/stdout -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/stderr -stderr_logfile_maxbytes=0 -stdout_events_enabled=true -stderr_events_enabled=true - -[program:watcherd] -command=watcherd -v -p /shared/httpd -a "vhost_gen.py -p %%p -n %%n -o %%p/__MASS_VHOST_TPL__/ -s __VERBOSE__" -d "rm /etc/httpd/vhost.d/%%n.conf" -t "/usr/local/apache2/bin/httpd -k restart" -#startsecs = 0 -#autorestart = false -#startretries = 1 -stdout_logfile=/dev/stdout -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/stderr -stderr_logfile_maxbytes=0 -stdout_events_enabled=true -stderr_events_enabled=true diff --git a/data/vhost-gen/main.yml b/data/vhost-gen/main.yml index 6dde619..c196eba 100644 --- a/data/vhost-gen/main.yml +++ b/data/vhost-gen/main.yml @@ -1,6 +1,6 @@ --- # Generic vhost generator configuration file. -# Location: /etc/vhost-gen/conf.yml +# Location: /etc/vhost-gen/main.yml # # See: https://github.com/devilbox/vhost-gen # @@ -74,6 +74,7 @@ custom: 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.py via '-n', however it is possible @@ -86,6 +87,14 @@ vhost: # to prepend another subdirectory here. docroot: suffix: + # SSL Definition + ssl: + dir_crt: /etc/httpd/cert/main + dir_key: /etc/httpd/cert/main + protocols: 'TLSv1 TLSv1.1 TLSv1.2' + honor_cipher_order: 'on' + ciphers: 'HIGH:!aNULL:!MD5' + # Log definition log: # Log file settings (error/access log) diff --git a/data/vhost-gen/conf.yml b/data/vhost-gen/mass.yml similarity index 93% rename from data/vhost-gen/conf.yml rename to data/vhost-gen/mass.yml index 754b38d..75b7226 100644 --- a/data/vhost-gen/conf.yml +++ b/data/vhost-gen/mass.yml @@ -1,6 +1,6 @@ --- # Generic vhost generator configuration file. -# Location: /etc/vhost-gen/conf.yml +# Location: /etc/vhost-gen/mass.yml # # See: https://github.com/devilbox/vhost-gen # @@ -74,6 +74,7 @@ custom: 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.py via '-n', however it is possible @@ -86,6 +87,14 @@ vhost: # to prepend another subdirectory here. docroot: suffix: __DOCROOT_SUFFIX__ + # SSL Definition + ssl: + 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) From bee7ebc8664a58a638111fb96ac1a6586e7fa1fb Mon Sep 17 00:00:00 2001 From: cytopia Date: Thu, 3 May 2018 09:29:10 +0200 Subject: [PATCH 2/2] Update README --- README.md | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 556ad05..bfb31c5 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,22 @@ -# Apache 2.2 Docker +# Apache 2.2 Docker image -[![Devilbox](https://raw.githubusercontent.com/cytopia/devilbox/master/.devilbox/www/htdocs/assets/img/devilbox_80.png)](https://github.com/cytopia/devilbox) +[![Build Status](https://travis-ci.org/devilbox/docker-apache-2.2.svg?branch=master)](https://travis-ci.org/devilbox/docker-apache-2.2) +[![release](https://img.shields.io/github/release/devilbox/docker-apache-2.2.svg)](https://github.com/devilbox/docker-apache-2.2/releases) +[![Join the chat at https://gitter.im/devilbox/Lobby](https://badges.gitter.im/devilbox/Lobby.svg)](https://gitter.im/devilbox/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Github](https://img.shields.io/badge/github-docker--apache--2.2-red.svg)](https://github.com/devilbox/docker-apache-2.2) +[![](https://images.microbadger.com/badges/license/devilbox/apache-2.2.svg)](https://microbadger.com/images/devilbox/apache-2.2 "apache-2.2") -This Docker image is part of the **[devilbox](https://github.com/cytopia/devilbox)**. +**[devilbox/docker-apache-2.2](https://github.com/devilbox/docker-apache-2.2)** -**Apache 2.2 | [Apache 2.4](https://github.com/devilbox/docker-apache-2.2) | [Nginx stable](https://github.com/devilbox/docker-nginx-stable) | [Nginx mainline](https://github.com/devilbox/docker-nginx-mainline)** - -[![Build Status](https://travis-ci.org/devilbox/docker-apache-2.2.svg?branch=master)](https://travis-ci.org/devilbox/docker-apache-2.2) [![](https://images.microbadger.com/badges/version/devilbox/apache-2.2.svg)](https://microbadger.com/images/devilbox/apache-2.2 "apache-2.2") [![](https://images.microbadger.com/badges/image/devilbox/apache-2.2.svg)](https://microbadger.com/images/devilbox/apache-2.2 "apache-2.2") [![](https://images.microbadger.com/badges/license/devilbox/apache-2.2.svg)](https://microbadger.com/images/devilbox/apache-2.2 "apache-2.2") +This image is based on the official **[Apache 2.2](https://hub.docker.com/_/httpd)** Docker image and extends it with the ability to have **virtual hosts created automatically**, as well as **adding SSL certificates** when creating new directories. For that to work, it integrates two tools that will take care about the whole process: **[watcherd](https://github.com/devilbox/watcherd)** and **[vhost-gen](https://github.com/devilbox/vhost-gen)**. -This image is based on the official **[Apache 2.2](https://hub.docker.com/_/httpd)** Docker image and extends it with the ability to have **virtual hosts created automatically** when adding new directories. For that to work, it integrates two tools that will take care about the whole process: **[watcherd](https://github.com/devilbox/watcherd)** and **[vhost-gen](https://github.com/devilbox/vhost-gen)**. +From a users perspective, you mount your local project directory into the container under `/shared/httpd`. Any directory then created in your local project directory wil spawn a new virtual host by the same name. Additional settings such as custom server names, PHP-FPM or even different Apache templates per project are supported as well. -From a users perspective, you mount your local project directory into the Docker under `/shared/httpd`. Any directory then created in your local project directory wil spawn a new virtual host by the same name. Additional settings such as custom server names, PHP-FPM or even different Apache templates per project are supported as well. - ----- +| Docker Hub | Upstream Project | +|------------|------------------| +| | | -Find me on **[Docker Hub](https://hub.docker.com/r/devilbox/apache-2.2)**: - -[![devilbox/apache-2.2](http://dockeri.co/image/devilbox/apache-2.2)](https://hub.docker.com/r/devilbox/apache-2.2/) - -**Latest build:** This container is built every night by [travis-ci](https://travis-ci.org/devilbox/docker-apache-2.2). +**Apache 2.2 | [Apache 2.4](https://github.com/devilbox/docker-apache-2.2) | [Nginx stable](https://github.com/devilbox/docker-nginx-stable) | [Nginx mainline](https://github.com/devilbox/docker-nginx-mainline)** ----