From 4dd4d7c56768424714384aa146b072f30a57347c Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 17 Sep 2015 19:09:29 -0700 Subject: [PATCH 01/15] initial pass at nginx proxy without VHOST. closes #1123 --- plugins/00_dokku-standard/commands | 12 +- plugins/certs/commands | 5 +- plugins/common/functions | 13 ++ plugins/domains/commands | 3 +- plugins/domains/functions | 7 +- plugins/nginx-vhosts/commands | 200 ++++-------------- plugins/nginx-vhosts/functions | 198 +++++++++++++++++ plugins/nginx-vhosts/post-deploy | 3 +- plugins/nginx-vhosts/post-domains-update | 3 +- .../nginx.conf.ssl_terminated.template | 4 +- .../templates/nginx.conf.template | 4 +- .../templates/nginx.ssl.conf.template | 12 +- 12 files changed, 287 insertions(+), 177 deletions(-) create mode 100755 plugins/nginx-vhosts/functions diff --git a/plugins/00_dokku-standard/commands b/plugins/00_dokku-standard/commands index af5e43770..051956413 100755 --- a/plugins/00_dokku-standard/commands +++ b/plugins/00_dokku-standard/commands @@ -193,8 +193,18 @@ case "$1" in echo "$SCHEME://$(< "$DOKKU_ROOT/VHOST")" else for PORT_FILE in $DOKKU_ROOT/$APP/PORT.*; do - echo "$SCHEME://$(< "$DOKKU_ROOT/HOSTNAME"):$(< "$PORT_FILE")" + echo "http://$(< "$DOKKU_ROOT/HOSTNAME"):$(< "$PORT_FILE") (container)" done + + DOKKU_NGINX_PORT=$(config_get $APP DOKKU_NGINX_PORT || true) + DOKKU_NGINX_SSL_PORT=$(config_get $APP DOKKU_NGINX_SSL_PORT || true) + + if [[ -n "$DOKKU_NGINX_PORT" ]]; then + echo "http://$(< "$DOKKU_ROOT/HOSTNAME"):$DOKKU_NGINX_PORT (nginx)" + fi + if [[ -n "$DOKKU_NGINX_SSL_PORT" ]]; then + echo "https://$(< "$DOKKU_ROOT/HOSTNAME"):$DOKKU_NGINX_SSL_PORT (nginx-ssl)" + fi fi ;; diff --git a/plugins/certs/commands b/plugins/certs/commands index ba6e62bc0..2dea833fc 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -2,6 +2,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/certs/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" is_tar_import() { [[ -t 0 ]] && return 1 @@ -57,7 +58,7 @@ certs_set() { mv "$KEY_FILE" "$DOKKU_ROOT/$APP/tls/server.key" cd $DOKKU_ROOT rm -rf $TEMP_DIR - dokku nginx:build-config $APP + nginx_build_config $APP } case "$1" in @@ -84,7 +85,7 @@ case "$1" in mkdir -p "$DOKKU_ROOT/$APP/tls" dokku_log_info1 "Installing certificate and key..." mv -f $TMP_WORK_DIR/server.key $TMP_WORK_DIR/server.crt $SSL_PATH - [[ -n "$DOMAIN" ]] && (dokku domains:add $APP $DOMAIN || dokku nginx:build-config $APP) + [[ -n "$DOMAIN" ]] && (dokku domains:add $APP $DOMAIN || nginx_build_config $APP) dokku_log_info1 "The following is a certificate signing request that can be used" dokku_log_info1 "to generate an 'officially' signed SSL certificate for $APP at $DOMAIN" dokku_log_info1 "by a CA of your choosing." diff --git a/plugins/common/functions b/plugins/common/functions index fecfce1ef..f14132c14 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -330,3 +330,16 @@ docker_cleanup() { # shellcheck disable=SC2046 docker rmi $(docker images -f 'dangling=true' -q) &> /dev/null & } + +get_open_port() { + while true; do + local port=$(shuf -i 1025-65535 -n 1) + if ! nc -z 0.0.0.0 $port; then + echo $port + return 0 + else + continue + fi + done + dokku_log_fail "no open ports found...wut?!" +} diff --git a/plugins/domains/commands b/plugins/domains/commands index b7dea8836..3788efb8e 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -3,6 +3,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/domains/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" RE_IPV4="([0-9]{1,3}[\.]){3}[0-9]{1,3}" @@ -94,7 +95,7 @@ case "$1" in echo "$DOMAIN" >> "$DOKKU_ROOT/$APP/VHOST" done # we need to restart the app to make sure we're binding to the appropriate network interface - dokku nginx:build-config $APP + nginx_build_config $APP plugn trigger post-domains-update $APP for DOMAIN in "$@"; do dokku_log_info1 "Added $DOMAIN to $APP" diff --git a/plugins/domains/functions b/plugins/domains/functions index 2a69c42a0..501f51908 100755 --- a/plugins/domains/functions +++ b/plugins/domains/functions @@ -3,6 +3,9 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" get_app_domains() { - local APP=$1; verify_app_name $APP - cat "$DOKKU_ROOT/$APP/VHOST" + local APP=$1; local VHOST_FILE="$DOKKU_ROOT/$APP/VHOST" + verify_app_name $APP + if [[ -f "$VHOST_FILE" ]]; then + cat "$VHOST_FILE" + fi } diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index 3851cdceb..d90349d79 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -1,168 +1,16 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/certs/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" -source "$PLUGIN_AVAILABLE_PATH/domains/functions" - -validate_nginx () { - set +e - sudo /usr/sbin/nginx -t > /dev/null 2>&1 - exit_code=$? - set -e - if [[ "$exit_code" -ne "0" ]]; then - sudo /usr/sbin/nginx -t - exit "$exit_code" - fi -} - -restart_nginx () { - case "$DOKKU_DISTRO" in - ubuntu) - sudo /etc/init.d/nginx reload > /dev/null - ;; - - opensuse) - sudo /sbin/service nginx reload > /dev/null - ;; - esac -} +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" case "$1" in nginx:build-config) - APP="$2"; DOKKU_APP_LISTEN_PORT="$3"; DOKKU_APP_LISTEN_IP="${4}" - verify_app_name "$APP" - VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" - URLS_PATH="$DOKKU_ROOT/$APP/URLS" - WILDCARD_SSL_PATH="$DOKKU_ROOT/tls" - APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" - APP_NGINX_TEMPLATE="$DOKKU_ROOT/$APP/nginx.conf.template" + APP="$2"; DOKKU_APP_LISTEN_PORT="$3"; DOKKU_APP_LISTEN_IP="$4" - if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -z "$DOKKU_APP_LISTEN_IP" ]]; then - shopt -s nullglob - for DOKKU_APP_IP_FILE in $DOKKU_ROOT/$APP/IP.web.*; do - DOKKU_APP_PORT_FILE=$(echo $DOKKU_APP_IP_FILE | sed -e "s:IP:PORT:g") - DOKKU_APP_LISTENER_IP=$(< $DOKKU_APP_IP_FILE) - DOKKU_APP_LISTENER_PORT=$(< $DOKKU_APP_PORT_FILE) + nginx_build_config $APP $DOKKU_APP_LISTEN_PORT $DOKKU_APP_LISTEN_IP - DOKKU_APP_LISTENERS+=" " - DOKKU_APP_LISTENERS+="$DOKKU_APP_LISTENER_IP:$DOKKU_APP_LISTENER_PORT" - DOKKU_APP_LISTENERS+=" " - done - shopt -u nullglob - fi - - DOKKU_APP_CIDS=($(get_app_container_ids $APP)) - docker cp "${DOKKU_APP_CIDS[0]}:/app/nginx.conf.template" "$DOKKU_ROOT/$APP/" 2> /dev/null || true - - eval "$(config_export global)" - eval "$(config_export app $APP)" - [[ -f "$APP_NGINX_TEMPLATE" ]] && NGINX_TEMPLATE="$APP_NGINX_TEMPLATE" && NGINX_CUSTOM_TEMPLATE="true" && dokku_log_info1 'Overriding default nginx.conf with detected nginx.conf.template' - - if [[ ! -n "$NO_VHOST" ]] && [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then - NONSSL_VHOSTS=$(get_app_domains $APP) - if [[ -n "$(is_ssl_enabled $APP)" ]]; then - SSL_HOSTNAME=$(get_ssl_hostnames $APP) - - [[ -n "$SSL_HOSTNAME" ]] && SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g') - if (egrep -q "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH); then - SSL_INUSE=true - else - dokku_log_info1 "No matching configured domains for $APP found in SSL certificate. Your app will not be configured with an SSL endpoint" - dokku_log_info1 "Please add appropriate domains via the dokku domains command" - dokku_log_info1 "Configured domains for app:" - for domain in $(echo $NONSSL_VHOSTS| xargs); do - dokku_log_info2 "$domain" - done - dokku_log_info1 "Domains found in SSL certificate:" - for domain in $(echo $SSL_HOSTNAME | xargs); do - dokku_log_info2 "$domain" - done - fi - if [[ "$(is_ssl_enabled $APP)" == "app" ]]; then - SSL_DIRECTIVES=$(cat <> $NGINX_CONF" - done <<< "$SSL_VHOSTS" - fi - - if [[ -n "$NONSSL_VHOSTS" ]]; then - NOSSL_SERVER_NAME=$(echo $NONSSL_VHOSTS | tr '\n' ' ') - xargs -i echo "-----> Configuring {}..." <<< "$NONSSL_VHOSTS" - if [[ -n "$DOKKU_SSL_TERMINATED" ]] && [[ -z "$NGINX_CUSTOM_TEMPLATE" ]]; then - NGINX_TEMPLATE="$(dirname $0)/templates/nginx.conf.ssl_terminated.template" - elif [[ -z "$NGINX_CUSTOM_TEMPLATE" ]]; then - NGINX_TEMPLATE="$(dirname $0)/templates/nginx.conf.template" - fi - eval "cat <<< \"$(< $NGINX_TEMPLATE)\" >> $NGINX_CONF" - fi - - if [[ -n "$DOKKU_APP_LISTEN_PORT" ]] && [[ -n "$DOKKU_APP_LISTEN_IP" ]]; then - echo "upstream $APP { server $DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT; }" >> $NGINX_CONF - elif [[ -n "$DOKKU_APP_LISTENERS" ]]; then - echo "upstream $APP { " >> $NGINX_CONF - for listener in $DOKKU_APP_LISTENERS; do - echo " server $listener;" >> $NGINX_CONF - done - echo "}" >> $NGINX_CONF - fi - - dokku_log_info1 "Creating $SCHEME nginx.conf" - mv $NGINX_CONF "$DOKKU_ROOT/$APP/nginx.conf" - - if is_deployed "$APP"; then - dokku_log_info1 "Running nginx-pre-reload" - plugn trigger nginx-pre-reload $APP $DOKKU_APP_LISTEN_PORT $DOKKU_APP_LISTEN_IP - - dokku_log_verbose "Reloading nginx" - validate_nginx && restart_nginx - fi - - echo "# THIS FILE IS GENERATED BY DOKKU - DO NOT EDIT, YOUR CHANGES WILL BE OVERWRITTEN" > $URLS_PATH - xargs -i echo "https://{}" <<< "${SSL_VHOSTS}" >> $URLS_PATH - xargs -i echo "http://{}" <<< "${NONSSL_VHOSTS}" >> $URLS_PATH - else - if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then - dokku_log_info1 "VHOST support disabled, deleting $APP/VHOST" - rm "$DOKKU_ROOT/$APP/VHOST" - fi - if [[ -f "$DOKKU_ROOT/$APP/URLS" ]]; then - dokku_log_info1 "VHOST support disabled, deleting $APP/URLS" - rm "$DOKKU_ROOT/$APP/URLS" - fi - if [[ -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then - dokku_log_info1 "VHOST support disabled, deleting nginx.conf" - rm "$DOKKU_ROOT/$APP/nginx.conf" - - if is_deployed "$APP"; then - dokku_log_info1 "VHOST support disabled, reloading nginx after nginx.conf deletion" - validate_nginx && restart_nginx - fi - fi - fi - ;; + ;; nginx:access-logs|nginx:error-logs) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 @@ -180,18 +28,52 @@ EOF fi tail "$NGINX_LOGS_ARGS" "$NGINX_LOGS_PATH" - ;; + ;; + + nginx:disable) + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + APP="$2" + + eval "$(config_export app $APP)" + if [[ -z "$NO_VHOST" ]]; then + config_set --no-restart $APP NO_NGINX=1 + config_set $APP NO_VHOST=1 + elif [[ -z "$NO_NGINX" ]]; then + config_set --no-restart $APP NO_NGINX=1 + nginx_build_config $APP + else + dokku_log_info1 "nginx is already disable for app ($APP)" + fi + ;; + + nginx:enable) + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + APP="$2" + + eval "$(config_export app $APP)" + if [[ -n "$NO_NGINX" ]]; then + config_unset --no-restart $APP NO_NGINX + unset NO_NGINX + nginx_build_config $APP + else + dokku_log_info1 "nginx is already enabled for app ($APP)" + fi + ;; help | nginx:help) cat<, (Re)builds nginx config for given app nginx:access-logs [-t], Show the nginx access logs for an application (-t follows) nginx:error-logs [-t], Show the nginx error logs for an application (-t follows) + nginx:disable , disable nginx for an application (forces container binding to external interface) + nginx:enable , enable nginx for an application EOF - ;; + ;; *) exit $DOKKU_NOT_IMPLEMENTED_EXIT - ;; + ;; esac diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions new file mode 100755 index 000000000..1382c92f1 --- /dev/null +++ b/plugins/nginx-vhosts/functions @@ -0,0 +1,198 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/certs/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +validate_nginx() { + set +e + sudo /usr/sbin/nginx -t > /dev/null 2>&1 + exit_code=$? + set -e + if [[ "$exit_code" -ne "0" ]]; then + sudo /usr/sbin/nginx -t + exit "$exit_code" + fi +} + +restart_nginx() { + case "$DOKKU_DISTRO" in + ubuntu) + sudo /etc/init.d/nginx reload > /dev/null + ;; + + opensuse) + sudo /sbin/service nginx reload > /dev/null + ;; + esac +} + +nginx_build_config() { + local APP="$1"; local DOKKU_APP_LISTEN_PORT="$2"; local DOKKU_APP_LISTEN_IP="$3" + verify_app_name "$APP" + VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" + URLS_PATH="$DOKKU_ROOT/$APP/URLS" + WILDCARD_SSL_PATH="$DOKKU_ROOT/tls" + APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + APP_NGINX_TEMPLATE="$DOKKU_ROOT/$APP/nginx.conf.template" + + eval "$(config_export global)" + eval "$(config_export app $APP)" + + if [[ ! -n "$NO_NGINX" ]]; then + if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -z "$DOKKU_APP_LISTEN_IP" ]]; then + shopt -s nullglob + for DOKKU_APP_IP_FILE in $DOKKU_ROOT/$APP/IP.web.*; do + DOKKU_APP_PORT_FILE=$(echo $DOKKU_APP_IP_FILE | sed -e "s:IP:PORT:g") + DOKKU_APP_LISTENER_IP=$(< $DOKKU_APP_IP_FILE) + DOKKU_APP_LISTENER_PORT=$(< $DOKKU_APP_PORT_FILE) + + DOKKU_APP_LISTENERS+=" " + DOKKU_APP_LISTENERS+="$DOKKU_APP_LISTENER_IP:$DOKKU_APP_LISTENER_PORT" + DOKKU_APP_LISTENERS+=" " + done + shopt -u nullglob + fi + + DOKKU_APP_CIDS=($(get_app_container_ids $APP)) + docker cp "${DOKKU_APP_CIDS[0]}:/app/nginx.conf.template" "$DOKKU_ROOT/$APP/" 2> /dev/null || true + + [[ -f "$APP_NGINX_TEMPLATE" ]] && NGINX_TEMPLATE="$APP_NGINX_TEMPLATE" && NGINX_CUSTOM_TEMPLATE="true" && dokku_log_info1 'Overriding default nginx.conf with detected nginx.conf.template' + + NGINX_CONF=$(mktemp -t "nginx.conf.XXXXXX") + SCHEME="http" + + if [[ -n "$NO_VHOST" ]]; then + if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then + dokku_log_info1 "VHOST support disabled, deleting $APP/VHOST" + rm "$DOKKU_ROOT/$APP/VHOST" + fi + fi + + if [[ -z "$DOKKU_NGINX_PORT" ]]; then + if [[ -n "$NO_VHOST" ]]; then + dokku_log_info1 "no nginx port set. setting to random open high port" + local NGINX_PORT=$(get_open_port) + else + local NGINX_PORT=80 + fi + config_set --no-restart $APP DOKKU_NGINX_PORT=${NGINX_PORT} + else + NGINX_PORT=$DOKKU_NGINX_PORT + fi + + NONSSL_VHOSTS=$(get_app_domains $APP) + if [[ -n "$(is_ssl_enabled $APP)" ]]; then + SSL_HOSTNAME=$(get_ssl_hostnames $APP) + SSL_INUSE=true + + [[ -n "$SSL_HOSTNAME" ]] && SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g') + if ! (egrep -q "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH &> /dev/null); then + dokku_log_info1 "No matching configured domains for $APP found in SSL certificate. Your app will show as insecure in a browser if accessed via SSL" + dokku_log_info1 "Please add appropriate domains via the dokku domains command" + [[ -n "$NONSSL_VHOSTS" ]] && dokku_log_info1 "Configured domains for app:" + for domain in $(echo $NONSSL_VHOSTS| xargs); do + dokku_log_info2 "$domain" + done + [[ -n "$SSL_HOSTNAME" ]] && dokku_log_info1 "Domains found in SSL certificate:" + for domain in $(echo $SSL_HOSTNAME | xargs); do + dokku_log_info2 "$domain" + done + fi + + if [[ "$(is_ssl_enabled $APP)" == "app" ]]; then + SSL_DIRECTIVES=$(cat < /dev/null || true) + + if [[ -z "$DOKKU_NGINX_SSL_PORT" ]]; then + if [[ -n "$NO_VHOST" ]]; then + dokku_log_info1 "no nginx ssl port set. setting to random open high port" + local NGINX_SSL_PORT=$(get_open_port) + else + NGINX_SSL_PORT=443 + fi + config_set --no-restart $APP DOKKU_NGINX_SSL_PORT=${NGINX_SSL_PORT} + else + local NGINX_SSL_PORT=$DOKKU_NGINX_SSL_PORT + fi + + while read line; do + [[ -z "$line" ]] && continue + dokku_log_info1 "Configuring SSL for $line..." + SSL_SERVER_NAME=$line + NOSSL_SERVER_NAME=$line + eval "cat <<< \"$(< $NGINX_TEMPLATE)\" >> $NGINX_CONF" + done <<< "$SSL_VHOSTS" + fi + + if [[ -n "$DOKKU_SSL_TERMINATED" ]] && [[ -z "$NGINX_CUSTOM_TEMPLATE" ]]; then + NGINX_TEMPLATE="$(dirname $0)/templates/nginx.conf.ssl_terminated.template" + elif [[ -z "$NGINX_CUSTOM_TEMPLATE" ]]; then + NGINX_TEMPLATE="$(dirname $0)/templates/nginx.conf.template" + fi + + if [[ -n "$NONSSL_VHOSTS" ]]; then + NOSSL_SERVER_NAME=$(echo $NONSSL_VHOSTS | tr '\n' ' ') + xargs -i echo "-----> Configuring {}..." <<< "$NONSSL_VHOSTS" + fi + eval "cat <<< \"$(< $NGINX_TEMPLATE)\" >> $NGINX_CONF" + [[ -n "$NO_VHOST" ]] && sed --in-place -n -e '/^.*server_name.*$/!p' $NGINX_CONF + + if [[ -n "$DOKKU_APP_LISTEN_PORT" ]] && [[ -n "$DOKKU_APP_LISTEN_IP" ]]; then + echo "upstream $APP { server $DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT; }" >> $NGINX_CONF + elif [[ -n "$DOKKU_APP_LISTENERS" ]]; then + echo "upstream $APP { " >> $NGINX_CONF + for listener in $DOKKU_APP_LISTENERS; do + echo " server $listener;" >> $NGINX_CONF + done + echo "}" >> $NGINX_CONF + fi + + dokku_log_info1 "Creating $SCHEME nginx.conf" + mv $NGINX_CONF "$DOKKU_ROOT/$APP/nginx.conf" + + if is_deployed "$APP"; then + dokku_log_info1 "Running nginx-pre-reload" + plugn trigger nginx-pre-reload $APP $DOKKU_APP_LISTEN_PORT $DOKKU_APP_LISTEN_IP + + dokku_log_verbose "Reloading nginx" + validate_nginx && restart_nginx + fi + + if [[ -z "$NO_VHOST" ]]; then + echo "# THIS FILE IS GENERATED BY DOKKU - DO NOT EDIT, YOUR CHANGES WILL BE OVERWRITTEN" > $URLS_PATH + xargs -i echo "https://{}" <<< "${SSL_VHOSTS}" >> $URLS_PATH + xargs -i echo "http://{}" <<< "${NONSSL_VHOSTS}" >> $URLS_PATH + fi + else + dokku_log_info1 "nginx support is disabled for app ($APP)." + if [[ -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then + dokku_log_info1 "deleting nginx.conf" + rm "$DOKKU_ROOT/$APP/nginx.conf" + + if is_deployed "$APP"; then + dokku_log_info1 "reloading nginx after nginx.conf deletion" + validate_nginx && restart_nginx + fi + fi + fi +} diff --git a/plugins/nginx-vhosts/post-deploy b/plugins/nginx-vhosts/post-deploy index e3fd84430..cee12b518 100755 --- a/plugins/nginx-vhosts/post-deploy +++ b/plugins/nginx-vhosts/post-deploy @@ -2,6 +2,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" APP="$1" if [[ -f "$DOKKU_ROOT/$APP/IP.web.1" ]] && [[ -f "$DOKKU_ROOT/$APP/PORT.web.1" ]]; then @@ -13,5 +14,5 @@ if [[ -f "$DOKKU_ROOT/$APP/IP.web.1" ]] && [[ -f "$DOKKU_ROOT/$APP/PORT.web.1" ] dokku domains:setup $APP fi - dokku nginx:build-config $APP + nginx_build_config $APP fi diff --git a/plugins/nginx-vhosts/post-domains-update b/plugins/nginx-vhosts/post-domains-update index 20abd9d5e..b62f24ac5 100755 --- a/plugins/nginx-vhosts/post-domains-update +++ b/plugins/nginx-vhosts/post-domains-update @@ -1,7 +1,8 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" APP="$1" -dokku nginx:build-config $APP +nginx_build_config $APP diff --git a/plugins/nginx-vhosts/templates/nginx.conf.ssl_terminated.template b/plugins/nginx-vhosts/templates/nginx.conf.ssl_terminated.template index bc7bc3a1d..642b0d653 100644 --- a/plugins/nginx-vhosts/templates/nginx.conf.ssl_terminated.template +++ b/plugins/nginx-vhosts/templates/nginx.conf.ssl_terminated.template @@ -1,8 +1,8 @@ # Nginx configuration when running behind a load balancer that terminates SSL # connections (e.g. AWS ELB) server { - listen [::]:80; - listen 80; + listen [::]:$NGINX_PORT; + listen $NGINX_PORT; server_name $NOSSL_SERVER_NAME; location / { proxy_pass http://$APP; diff --git a/plugins/nginx-vhosts/templates/nginx.conf.template b/plugins/nginx-vhosts/templates/nginx.conf.template index ad29248c2..23a88e1da 100644 --- a/plugins/nginx-vhosts/templates/nginx.conf.template +++ b/plugins/nginx-vhosts/templates/nginx.conf.template @@ -1,6 +1,6 @@ server { - listen [::]:80; - listen 80; + listen [::]:$NGINX_PORT; + listen $NGINX_PORT; server_name $NOSSL_SERVER_NAME; access_log /var/log/nginx/${APP}-access.log; error_log /var/log/nginx/${APP}-error.log; diff --git a/plugins/nginx-vhosts/templates/nginx.ssl.conf.template b/plugins/nginx-vhosts/templates/nginx.ssl.conf.template index 312cd83c3..ac49e6e9b 100644 --- a/plugins/nginx-vhosts/templates/nginx.ssl.conf.template +++ b/plugins/nginx-vhosts/templates/nginx.ssl.conf.template @@ -1,22 +1,22 @@ server { - listen [::]:80; - listen 80; + listen [::]:$NGINX_PORT; + listen $NGINX_PORT; server_name $NOSSL_SERVER_NAME; access_log /var/log/nginx/${APP}-access.log; error_log /var/log/nginx/${APP}-error.log; - return 301 https://\$host\$request_uri; + return 301 https://\$host:$NGINX_SSL_PORT\$request_uri; } server { - listen [::]:443 ssl spdy; - listen 443 ssl spdy; + listen [::]:$NGINX_SSL_PORT ssl spdy; + listen $NGINX_SSL_PORT ssl spdy; server_name $SSL_SERVER_NAME; access_log /var/log/nginx/${APP}-access.log; error_log /var/log/nginx/${APP}-error.log; $SSL_DIRECTIVES keepalive_timeout 70; - add_header Alternate-Protocol 443:npn-spdy/2; + add_header Alternate-Protocol $NGINX_SSL_PORT:npn-spdy/2; location / { gzip on; From de6ccf4ce2b1bf87750a27e49c70a4754cc41290 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 17 Sep 2015 21:15:18 -0700 Subject: [PATCH 02/15] cleanup unnecessary failure message --- plugins/common/functions | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/common/functions b/plugins/common/functions index f14132c14..2e6aa2891 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -341,5 +341,4 @@ get_open_port() { continue fi done - dokku_log_fail "no open ports found...wut?!" } From 943e9b387c33fc3c5711c748adddfcd116ded7bc Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 17 Sep 2015 21:40:34 -0700 Subject: [PATCH 03/15] fixing tests --- plugins/nginx-vhosts/functions | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index 1382c92f1..5dfeecac4 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -68,6 +68,10 @@ nginx_build_config() { dokku_log_info1 "VHOST support disabled, deleting $APP/VHOST" rm "$DOKKU_ROOT/$APP/VHOST" fi + if [[ -f "$DOKKU_ROOT/$APP/URLS" ]]; then + dokku_log_info1 "VHOST support disabled, deleting $APP/URLS" + rm "$DOKKU_ROOT/$APP/URLS" + fi fi if [[ -z "$DOKKU_NGINX_PORT" ]]; then @@ -155,7 +159,9 @@ EOF xargs -i echo "-----> Configuring {}..." <<< "$NONSSL_VHOSTS" fi eval "cat <<< \"$(< $NGINX_TEMPLATE)\" >> $NGINX_CONF" - [[ -n "$NO_VHOST" ]] && sed --in-place -n -e '/^.*server_name.*$/!p' $NGINX_CONF + if [[ -n "$NO_VHOST" ]] || [[ -z "$NONSSL_VHOSTS" ]];then + sed --in-place -n -e '/^.*server_name.*$/!p' $NGINX_CONF + fi if [[ -n "$DOKKU_APP_LISTEN_PORT" ]] && [[ -n "$DOKKU_APP_LISTEN_IP" ]]; then echo "upstream $APP { server $DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT; }" >> $NGINX_CONF @@ -178,7 +184,7 @@ EOF validate_nginx && restart_nginx fi - if [[ -z "$NO_VHOST" ]]; then + if [[ ! -n "$NO_VHOST" ]] && [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then echo "# THIS FILE IS GENERATED BY DOKKU - DO NOT EDIT, YOUR CHANGES WILL BE OVERWRITTEN" > $URLS_PATH xargs -i echo "https://{}" <<< "${SSL_VHOSTS}" >> $URLS_PATH xargs -i echo "http://{}" <<< "${NONSSL_VHOSTS}" >> $URLS_PATH From 89dd7839249a0185ec9a56a5e57279b1ec663957 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 17 Sep 2015 21:52:07 -0700 Subject: [PATCH 04/15] [ci skip] update nginx docs --- docs/nginx.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/nginx.md b/docs/nginx.md index 1490a7c3b..712770abe 100644 --- a/docs/nginx.md +++ b/docs/nginx.md @@ -2,6 +2,14 @@ Dokku uses nginx as it's server for routing requests to specific applications. By default, access and error logs are written for each app to `/var/log/nginx/${APP}-access.log` and `/var/log/nginx/${APP}-error.log` respectively +``` +nginx:access-logs [-t] Show the nginx access logs for an application (-t follows) +nginx:build-config (Re)builds nginx config for given app +nginx:disable disable nginx for an application (forces container binding to external interface) +nginx:enable enable nginx for an application +nginx:error-logs [-t] Show the nginx error logs for an application (-t follows) +``` + ## TLS/SPDY support Dokku provides easy TLS/SPDY support out of the box. This can be done app-by-app or for all subdomains at once. Note that whenever TLS support is enabled SPDY is also enabled. @@ -172,7 +180,7 @@ If desired, it is possible to disable vhosts by setting the `NO_VHOST` environme dokku config:set myapp NO_VHOST=1 ``` -On subsequent deploys, the nginx virtualhost will be discarded. This is useful when deploying internal-facing services that should not be publicly routeable. +On subsequent deploys, the nginx virtualhost will be discarded. This is useful when deploying internal-facing services that should not be publicly routeable. As of 0.4.0, nginx will still be configured to proxy your app on some random high port. This allows internal services to maintain the same port between deployments. You may change this port by setting `DOKKU_NGINX_PORT` and/or `DOKKU_NGINX_SSL_PORT` (for services configured to use SSL.) ### Domains plugin From f84c2bf6d8cf1cbee975428f9268e4877825e7a9 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 17 Sep 2015 21:54:37 -0700 Subject: [PATCH 05/15] be explicit about our template path since others are calling us as a function --- plugins/nginx-vhosts/functions | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index 5dfeecac4..69b763cec 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -119,7 +119,7 @@ EOF if [[ -n "$SSL_INUSE" ]]; then SCHEME="https" - [[ -z "$NGINX_TEMPLATE" ]] && NGINX_TEMPLATE="$(dirname $0)/templates/nginx.ssl.conf.template" + [[ -z "$NGINX_TEMPLATE" ]] && NGINX_TEMPLATE="$PLUGIN_AVAILABLE_PATH/nginx-vhosts/templates/nginx.ssl.conf.template" if [[ -z "$NO_VHOST" ]]; then SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH || true) else @@ -149,9 +149,9 @@ EOF fi if [[ -n "$DOKKU_SSL_TERMINATED" ]] && [[ -z "$NGINX_CUSTOM_TEMPLATE" ]]; then - NGINX_TEMPLATE="$(dirname $0)/templates/nginx.conf.ssl_terminated.template" + NGINX_TEMPLATE="$PLUGIN_AVAILABLE_PATH/nginx-vhosts/templates/nginx.conf.ssl_terminated.template" elif [[ -z "$NGINX_CUSTOM_TEMPLATE" ]]; then - NGINX_TEMPLATE="$(dirname $0)/templates/nginx.conf.template" + NGINX_TEMPLATE="$PLUGIN_AVAILABLE_PATH/nginx-vhosts/templates/nginx.conf.template" fi if [[ -n "$NONSSL_VHOSTS" ]]; then From e07ae7ad6a24a1c69674add248014bfe5c7f51e2 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 17 Sep 2015 22:32:57 -0700 Subject: [PATCH 06/15] include new port variables in custom nginx templates --- tests/unit/test_helper.bash | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/unit/test_helper.bash b/tests/unit/test_helper.bash index 5e8d3353c..32cba7a27 100644 --- a/tests/unit/test_helper.bash +++ b/tests/unit/test_helper.bash @@ -175,20 +175,20 @@ custom_ssl_nginx_template() { [[ -z "$APP" ]] && APP="$TEST_APP" cat< $DOKKU_ROOT/$APP/nginx.conf.template server { - listen [::]:80; - listen 80; + listen [::]:\$NGINX_PORT; + listen \$NGINX_PORT; server_name \$NOSSL_SERVER_NAME; - return 301 https://\$SSL_SERVER_NAME\\\$request_uri; + return 301 https://\\\$host:\$NGINX_SSL_PORT\\\$request_uri; } server { - listen [::]:443 ssl spdy; - listen 443 ssl spdy; + listen [::]:\$NGINX_SSL_PORT ssl spdy; + listen \$NGINX_SSL_PORT ssl spdy; server_name \$SSL_SERVER_NAME; \$SSL_DIRECTIVES keepalive_timeout 70; - add_header Alternate-Protocol 443:npn-spdy/2; + add_header Alternate-Protocol \$NGINX_SSL_PORT:npn-spdy/2; location / { proxy_pass http://\$APP; proxy_http_version 1.1; @@ -210,8 +210,8 @@ custom_nginx_template() { [[ -z "$APP" ]] && APP="$TEST_APP" cat< $DOKKU_ROOT/$APP/nginx.conf.template server { - listen [::]:80; - listen 80; + listen [::]:\$NGINX_PORT; + listen \$NGINX_PORT; server_name \$NOSSL_SERVER_NAME; location / { From 9efa8beb81a81c064af080ca059a9946c66b2076 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 17 Sep 2015 22:35:13 -0700 Subject: [PATCH 07/15] redirect includes port now --- tests/unit/nginx-vhosts.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/nginx-vhosts.bats b/tests/unit/nginx-vhosts.bats index fe2cf114a..1436c6a68 100644 --- a/tests/unit/nginx-vhosts.bats +++ b/tests/unit/nginx-vhosts.bats @@ -18,7 +18,7 @@ teardown() { assert_ssl_domain() { local domain=$1 assert_app_domain "${domain}" - assert_http_redirect "http://${domain}" "https://${domain}/" + assert_http_redirect "http://${domain}" "https://${domain}:443/" assert_http_success "https://${domain}" } From 6e7ca94d84a1b2db67847c8c718134f97a92ea16 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 17 Sep 2015 22:46:58 -0700 Subject: [PATCH 08/15] set SSL_VHOSTS to HOSTNAME if NO_VHOST is set and filter out server_name stanza if we have no hosts" --- plugins/nginx-vhosts/functions | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index 69b763cec..8b8979885 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -123,7 +123,7 @@ EOF if [[ -z "$NO_VHOST" ]]; then SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH || true) else - SSL_VHOSTS="fakedomain.com" + SSL_VHOSTS=$(< $DOKKU_ROOT/HOSTNAME) fi NONSSL_VHOSTS=$(egrep -v "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH 2> /dev/null || true) @@ -159,7 +159,7 @@ EOF xargs -i echo "-----> Configuring {}..." <<< "$NONSSL_VHOSTS" fi eval "cat <<< \"$(< $NGINX_TEMPLATE)\" >> $NGINX_CONF" - if [[ -n "$NO_VHOST" ]] || [[ -z "$NONSSL_VHOSTS" ]];then + if [[ -n "$NO_VHOST" ]] || ([[ -z "$NONSSL_VHOSTS" ]] && [[ -z "$SSL_VHOSTS" ]]); then sed --in-place -n -e '/^.*server_name.*$/!p' $NGINX_CONF fi From b9ecb32d3f8984600e80286793dd538188946d5d Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Wed, 16 Sep 2015 23:56:08 -0700 Subject: [PATCH 09/15] Reduce deploy trace output for multi-container applications This reduces deploy output by moving `config:get` calls out of the main loop. Since the values are the same for each iteration, it does not make sense to re-retrieve them each time. --- dokku | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dokku b/dokku index c3dd36337..8469e8b5f 100755 --- a/dokku +++ b/dokku @@ -80,6 +80,14 @@ case "$1" in DOKKU_RESTART_LIMIT=$(dokku config:get $APP DOKKU_RESTART_LIMIT || echo 10) DOKKU_RESTART_LIMIT=${DOKKU_RESTART_LIMIT:=10} + DOKKU_APP_SKIP_ALL_CHECKS=$(dokku config:get $APP DOKKU_SKIP_ALL_CHECKS || true) + DOKKU_APP_SKIP_DEFAULT_CHECKS=$(dokku config:get $APP DOKKU_SKIP_DEFAULT_CHECKS || true) + DOKKU_GLOBAL_SKIP_ALL_CHECKS=$(dokku config:get --global DOKKU_SKIP_ALL_CHECKS || true) + DOKKU_GLOBAL_SKIP_DEFAULT_CHECKS=$(dokku config:get --global DOKKU_SKIP_DEFAULT_CHECKS || true) + + DOKKU_SKIP_ALL_CHECKS=${DOKKU_APP_SKIP_ALL_CHECKS:="$DOKKU_GLOBAL_SKIP_ALL_CHECKS"} + DOKKU_SKIP_DEFAULT_CHECKS=${DOKKU_APP_SKIP_DEFAULT_CHECKS:="$DOKKU_GLOBAL_SKIP_DEFAULT_CHECKS"} + while read line || [[ -n "$line" ]]; do TRIM=${line%#*} PROC_TYPE=${TRIM%%=*} @@ -127,14 +135,6 @@ case "$1" in kill -9 $$ } - DOKKU_APP_SKIP_ALL_CHECKS=$(dokku config:get $APP DOKKU_SKIP_ALL_CHECKS || true) - DOKKU_APP_SKIP_DEFAULT_CHECKS=$(dokku config:get $APP DOKKU_SKIP_DEFAULT_CHECKS || true) - DOKKU_GLOBAL_SKIP_ALL_CHECKS=$(dokku config:get --global DOKKU_SKIP_ALL_CHECKS || true) - DOKKU_GLOBAL_SKIP_DEFAULT_CHECKS=$(dokku config:get --global DOKKU_SKIP_DEFAULT_CHECKS || true) - - DOKKU_SKIP_ALL_CHECKS=${DOKKU_APP_SKIP_ALL_CHECKS:="$DOKKU_GLOBAL_SKIP_ALL_CHECKS"} - DOKKU_SKIP_DEFAULT_CHECKS=${DOKKU_APP_SKIP_DEFAULT_CHECKS:="$DOKKU_GLOBAL_SKIP_DEFAULT_CHECKS"} - # run checks first, then post-deploy hooks, which switches Nginx traffic if [[ "$DOKKU_SKIP_ALL_CHECKS" = "true" ]]; then dokku_log_info1 "Skipping pre-flight checks" From 1e543afb7851e9efe8efd79964d16d0766219da4 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Wed, 16 Sep 2015 23:57:23 -0700 Subject: [PATCH 10/15] Retrieve default docker args a single time --- dokku | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dokku b/dokku index 8469e8b5f..b15993024 100755 --- a/dokku +++ b/dokku @@ -88,6 +88,8 @@ case "$1" in DOKKU_SKIP_ALL_CHECKS=${DOKKU_APP_SKIP_ALL_CHECKS:="$DOKKU_GLOBAL_SKIP_ALL_CHECKS"} DOKKU_SKIP_DEFAULT_CHECKS=${DOKKU_APP_SKIP_DEFAULT_CHECKS:="$DOKKU_GLOBAL_SKIP_DEFAULT_CHECKS"} + DOKKU_DEFAULT_DOCKER_ARGS=$(: | plugn trigger docker-args-deploy $APP $IMAGE_TAG) + while read line || [[ -n "$line" ]]; do TRIM=${line%#*} PROC_TYPE=${TRIM%%=*} @@ -101,9 +103,9 @@ case "$1" in DOKKU_PORT_FILE="$DOKKU_ROOT/$APP/PORT.$PROC_TYPE.$CONTAINER_INDEX" # start the app - DOCKER_ARGS=" -e DYNO='$PROC_TYPE.$CONTAINER_INDEX' " + DOCKER_ARGS="$DOKKU_DEFAULT_DOCKER_ARGS" + DOCKER_ARGS+=" -e DYNO='$PROC_TYPE.$CONTAINER_INDEX' " DOCKER_ARGS+=" --restart=on-failure:$DOKKU_RESTART_LIMIT" - DOCKER_ARGS+=$(: | plugn trigger docker-args-deploy $APP $IMAGE_TAG) [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true " BIND_EXTERNAL=$(plugn trigger bind-external-ip $APP) From 467264d31f929c13134ecd95eed08cc0ef99eded Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 17 Sep 2015 02:00:23 -0700 Subject: [PATCH 11/15] Drop another ~1k lines from DOKKU_TRACE output --- plugins/20_events/commands | 3 +-- plugins/backup/commands | 3 +-- plugins/docker-options/commands | 15 ++++++----- plugins/domains/commands | 21 +--------------- plugins/domains/functions | 36 +++++++++++++++++++++++++++ plugins/nginx-vhosts/bind-external-ip | 1 - 6 files changed, 46 insertions(+), 33 deletions(-) diff --git a/plugins/20_events/commands b/plugins/20_events/commands index 11f3a2b15..d3d0a16f4 100755 --- a/plugins/20_events/commands +++ b/plugins/20_events/commands @@ -2,8 +2,6 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -PLUGIN_DIR="$(dirname $0)" - case "$1" in events) if [[ -f $DOKKU_EVENTS_LOGFILE ]]; then @@ -27,6 +25,7 @@ case "$1" in ;; events:list) + PLUGIN_DIR="$(dirname $0)" if [[ "$DOKKU_EVENTS" ]]; then logged="$(find $PLUGIN_DIR -type l -printf '%f ' | sort)" dokku_col_log_info2_quiet "Events currently logged" diff --git a/plugins/backup/commands b/plugins/backup/commands index 2fa160979..9cd99a5ca 100755 --- a/plugins/backup/commands +++ b/plugins/backup/commands @@ -1,10 +1,9 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -CURRENT_BACKUP_VERSION=1 - case "$1" in backup:export) + CURRENT_BACKUP_VERSION=1 OUTPUT_FILE="$2" BACKUP_DIR="$DOKKU_ROOT" diff --git a/plugins/docker-options/commands b/plugins/docker-options/commands index b7f63c55d..4148605d6 100755 --- a/plugins/docker-options/commands +++ b/plugins/docker-options/commands @@ -2,10 +2,6 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -PHASES=(build deploy run) - -FILE_PREFIX="DOCKER_OPTIONS_" - get_app() { [[ -z $1 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$1" @@ -25,17 +21,19 @@ get_phases() { verify_phase() { local phase - for phase in "${PHASES[@]}"; do + local phases=(build deploy run) + for phase in "${phases[@]}"; do if [[ "$phase" = "$1" ]]; then return 0 fi done - dokku_log_fail "Phase(s) must be one of [${PHASES[@]}]" + dokku_log_fail "Phase(s) must be one of [${phases[@]}]" } get_phase_file_path() { local phase=$1 - phase_file_path="${DOKKU_ROOT}/${APP}/${FILE_PREFIX}${phase^^}" + local prefix="DOCKER_OPTIONS_" + phase_file_path="${DOKKU_ROOT}/${APP}/${prefix}${phase^^}" } create_phase_file_if_required() { @@ -53,7 +51,8 @@ display_phase_options() { } display_all_phases_options() { - for phase in "${PHASES[@]}"; do + local phases=(build deploy run) + for phase in "${phases[@]}"; do get_phase_file_path $phase if [[ -s $phase_file_path ]]; then display_phase_options $phase $phase_file_path diff --git a/plugins/domains/commands b/plugins/domains/commands index b7dea8836..f134e151c 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -4,26 +4,6 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/domains/functions" -RE_IPV4="([0-9]{1,3}[\.]){3}[0-9]{1,3}" - -RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 -RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 -RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: -RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) -RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 - -# Ensure the ip address continues to the end of the line -# Fixes using a wildcard dns service such as xip.io which allows for *..xip.io -RE_IPV4="${RE_IPV4}\$" -RE_IPV6="${RE_IPV6}\$" - case "$1" in domains) [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" @@ -43,6 +23,7 @@ case "$1" in [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2"; VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" + RE_IPV4="$(get_ipv4_regex)"; RE_IPV6="$(get_ipv6_regex)" if [[ ! -f $VHOST_PATH ]]; then if [[ -f "$DOKKU_ROOT/VHOST" ]]; then diff --git a/plugins/domains/functions b/plugins/domains/functions index 2a69c42a0..0fbf9b774 100755 --- a/plugins/domains/functions +++ b/plugins/domains/functions @@ -6,3 +6,39 @@ get_app_domains() { local APP=$1; verify_app_name $APP cat "$DOKKU_ROOT/$APP/VHOST" } + +_ipv4_regex() { + echo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" +} + +_ipv6_regex() { + local RE_IPV4="$(_ipv4_regex)" + local RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 + RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 + RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: + RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) + RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 + echo "$RE_IPV6" +} + + +get_ipv4_regex() { + local RE_IPV4="$(_ipv4_regex)" + # Ensure the ip address continues to the end of the line + # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io + echo "${RE_IPV4}\$" +} + +get_ipv6_regex() { + local RE_IPV6="$(_ipv4_regex)" + # Ensure the ip address continues to the end of the line + # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io + echo "${RE_IPV6}\$" +} diff --git a/plugins/nginx-vhosts/bind-external-ip b/plugins/nginx-vhosts/bind-external-ip index b5f5c01d5..822989cfd 100755 --- a/plugins/nginx-vhosts/bind-external-ip +++ b/plugins/nginx-vhosts/bind-external-ip @@ -20,7 +20,6 @@ RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: f RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 - # Ensure the ip address continues to the end of the line # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io RE_IPV4="${RE_IPV4}\$" From 70511c340dfea9bff4c0b5172280705eccbc90e1 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 17 Sep 2015 02:43:51 -0700 Subject: [PATCH 12/15] Check if command is implemented in a plugin before executing plugin code Because of how plugin commands are implemented, their output can be incredibly verbose. Rather than executing even the `set -eo pipefail` parts of a plugin, we immediately check if the command is implemented by a plugin. If it is not, then we continue on as normal. One side-effect of this change is that plugin commands need to be duplicated again: - once in the command array - once for the actual body of the command - once in the help output This is also quite hackish, and probably not the best way to decrease trace output. Note that we drop approximately 2k lines worth of logs with this change. --- plugins/00_dokku-standard/commands | 1 + plugins/20_events/commands | 1 + plugins/apps/commands | 1 + plugins/backup/commands | 1 + plugins/certs/commands | 1 + plugins/config/commands | 1 + plugins/docker-options/commands | 1 + plugins/domains/commands | 1 + plugins/enter/commands | 1 + plugins/nginx-vhosts/commands | 1 + plugins/plugin/commands | 1 + plugins/ps/commands | 1 + plugins/shell/commands | 1 + plugins/tags/commands | 1 + plugins/tar/commands | 1 + 15 files changed, 15 insertions(+) diff --git a/plugins/00_dokku-standard/commands b/plugins/00_dokku-standard/commands index af5e43770..1e3d39b3e 100755 --- a/plugins/00_dokku-standard/commands +++ b/plugins/00_dokku-standard/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " build release trace delete ls logs run url urls version help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" diff --git a/plugins/20_events/commands b/plugins/20_events/commands index d3d0a16f4..582b5c38f 100755 --- a/plugins/20_events/commands +++ b/plugins/20_events/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " events events:on events:off events:list help events:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" diff --git a/plugins/apps/commands b/plugins/apps/commands index 93052e0d0..a73e97975 100755 --- a/plugins/apps/commands +++ b/plugins/apps/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " apps apps:create apps:destroy help apps:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" diff --git a/plugins/backup/commands b/plugins/backup/commands index 9cd99a5ca..90f28a4ad 100755 --- a/plugins/backup/commands +++ b/plugins/backup/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " backup:export backup:import help backup:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x case "$1" in diff --git a/plugins/certs/commands b/plugins/certs/commands index ba6e62bc0..1ecacd41c 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " certs:add certs:generate certs:info certs:remove certs:update help certs:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/certs/functions" diff --git a/plugins/config/commands b/plugins/config/commands index 191af9f52..f5b929449 100755 --- a/plugins/config/commands +++ b/plugins/config/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " config config:get config:set config:unset help config:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" diff --git a/plugins/docker-options/commands b/plugins/docker-options/commands index 4148605d6..a1396c1cc 100755 --- a/plugins/docker-options/commands +++ b/plugins/docker-options/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " docker-options docker-options:add docker-options:remove help docker-options:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" diff --git a/plugins/domains/commands b/plugins/domains/commands index f134e151c..36f4ffa2c 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " domains domains:setup domains:add domains:clear domains:remove help domains:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" diff --git a/plugins/enter/commands b/plugins/enter/commands index b8e0bdbdc..b69217e98 100755 --- a/plugins/enter/commands +++ b/plugins/enter/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " enter help enter:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index 3851cdceb..c3508c967 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " nginx:build-config nginx:access-logs nginx:error-logs help nginx:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/certs/functions" diff --git a/plugins/plugin/commands b/plugins/plugin/commands index 8df025c37..d4eb65327 100755 --- a/plugins/plugin/commands +++ b/plugins/plugin/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " plugin plugin:install plugin:install-dependencies plugin:update plugin:disable plugin:enable plugin:uninstall help plugin:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/plugin/functions" diff --git a/plugins/ps/commands b/plugins/ps/commands index d9614c623..3e0a7357a 100755 --- a/plugins/ps/commands +++ b/plugins/ps/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " ps ps:start ps:stop ps:rebuild ps:rebuildall ps:restart ps:restartall ps:scale help ps:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/ps/functions" diff --git a/plugins/shell/commands b/plugins/shell/commands index f64e231aa..16fec26f4 100755 --- a/plugins/shell/commands +++ b/plugins/shell/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " shell help shell:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x case "$1" in diff --git a/plugins/tags/commands b/plugins/tags/commands index 58061e835..9990485a9 100755 --- a/plugins/tags/commands +++ b/plugins/tags/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " tags tags:create tags:deploy tags:destroy help tags:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/tags/functions" diff --git a/plugins/tar/commands b/plugins/tar/commands index 76da3766f..e57faeabd 100755 --- a/plugins/tar/commands +++ b/plugins/tar/commands @@ -1,4 +1,5 @@ #!/usr/bin/env bash +[[ " tar-from tar:from tar-in tar:in tar-build tar-build-locked help tar:help " == *" $1 "* ]] || exit $DOKKU_NOT_IMPLEMENTED_EXIT set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" From d3c218f95e7d8daff301f7aa968eb8d0ad50bd2c Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 17 Sep 2015 02:44:05 -0700 Subject: [PATCH 13/15] Add help commands to docker-options and tar plugins --- plugins/docker-options/commands | 2 +- plugins/tar/commands | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/docker-options/commands b/plugins/docker-options/commands index a1396c1cc..2a9589978 100755 --- a/plugins/docker-options/commands +++ b/plugins/docker-options/commands @@ -139,7 +139,7 @@ case "$1" in ;; # Display usage help - help) + help | docker-options:help) cat<, Display apps docker options for all phases docker-options , Display apps docker options for phase (comma separated phase list) diff --git a/plugins/tar/commands b/plugins/tar/commands index e57faeabd..519ae4e15 100755 --- a/plugins/tar/commands +++ b/plugins/tar/commands @@ -58,7 +58,7 @@ case "$1" in fi ;; - help) + help | tar:help) cat && cat<, Reads an tarball containing the app from stdin tar:from , Loads an app tarball from url. From f914e6207b24ee9dc8cd68215e8487d5cb7a42d0 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 18 Sep 2015 16:15:26 -0400 Subject: [PATCH 14/15] Consolidate ipv4/ipv6 regex declarations behing nginx-vhosts plugin --- plugins/domains/commands | 1 + plugins/domains/functions | 36 ------------------------- plugins/nginx-vhosts/bind-external-ip | 22 ++-------------- plugins/nginx-vhosts/functions | 38 +++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 56 deletions(-) create mode 100755 plugins/nginx-vhosts/functions diff --git a/plugins/domains/commands b/plugins/domains/commands index 36f4ffa2c..d71c10db7 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -4,6 +4,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/domains/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" case "$1" in domains) diff --git a/plugins/domains/functions b/plugins/domains/functions index 0fbf9b774..2a69c42a0 100755 --- a/plugins/domains/functions +++ b/plugins/domains/functions @@ -6,39 +6,3 @@ get_app_domains() { local APP=$1; verify_app_name $APP cat "$DOKKU_ROOT/$APP/VHOST" } - -_ipv4_regex() { - echo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" -} - -_ipv6_regex() { - local RE_IPV4="$(_ipv4_regex)" - local RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 - RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 - RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: - RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) - RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) - RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 - echo "$RE_IPV6" -} - - -get_ipv4_regex() { - local RE_IPV4="$(_ipv4_regex)" - # Ensure the ip address continues to the end of the line - # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io - echo "${RE_IPV4}\$" -} - -get_ipv6_regex() { - local RE_IPV6="$(_ipv4_regex)" - # Ensure the ip address continues to the end of the line - # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io - echo "${RE_IPV6}\$" -} diff --git a/plugins/nginx-vhosts/bind-external-ip b/plugins/nginx-vhosts/bind-external-ip index 822989cfd..5c1456333 100755 --- a/plugins/nginx-vhosts/bind-external-ip +++ b/plugins/nginx-vhosts/bind-external-ip @@ -4,26 +4,8 @@ source "$PLUGIN_AVAILABLE_PATH/config/functions" APP="$1" NO_VHOST=$(config_get $APP NO_VHOST || true) - -RE_IPV4="([0-9]{1,3}[\.]){3}[0-9]{1,3}" - -RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 -RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 -RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: -RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) -RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 - -# Ensure the ip address continues to the end of the line -# Fixes using a wildcard dns service such as xip.io which allows for *..xip.io -RE_IPV4="${RE_IPV4}\$" -RE_IPV6="${RE_IPV6}\$" +RE_IPV4="$(get_ipv4_regex)" +RE_IPV6="$(get_ipv6_regex)" [[ -f "$DOKKU_ROOT/VHOST" ]] && GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions new file mode 100755 index 000000000..a246cb229 --- /dev/null +++ b/plugins/nginx-vhosts/functions @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +_ipv4_regex() { + echo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" +} + +_ipv6_regex() { + local RE_IPV4="$(_ipv4_regex)" + local RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 + RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 + RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: + RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) + RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) + RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 + echo "$RE_IPV6" +} + +get_ipv4_regex() { + local RE_IPV4="$(_ipv4_regex)" + # Ensure the ip address continues to the end of the line + # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io + echo "${RE_IPV4}\$" +} + +get_ipv6_regex() { + local RE_IPV6="$(_ipv4_regex)" + # Ensure the ip address continues to the end of the line + # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io + echo "${RE_IPV6}\$" +} From 3e18d9aff9cae247f6cf1436e125dfd248bfcaa7 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Fri, 18 Sep 2015 15:46:46 -0700 Subject: [PATCH 15/15] create functions for app/global vhost detection. make VHOST setting more explicit --- docs/nginx.md | 2 +- plugins/00_dokku-standard/commands | 7 +- plugins/common/functions | 2 +- plugins/config/functions | 1 + plugins/domains/commands | 3 +- plugins/domains/functions | 6 +- plugins/nginx-vhosts/bind-external-ip | 36 +-------- plugins/nginx-vhosts/commands | 18 ++--- plugins/nginx-vhosts/functions | 106 +++++++++++++++++++++----- plugins/nginx-vhosts/post-deploy | 7 +- tests/unit/core_ports.bats | 20 ++--- 11 files changed, 123 insertions(+), 85 deletions(-) diff --git a/docs/nginx.md b/docs/nginx.md index 712770abe..a27347ab1 100644 --- a/docs/nginx.md +++ b/docs/nginx.md @@ -174,7 +174,7 @@ You can also use the built-in `domains` plugin to handle: ### Disabling VHOSTS -If desired, it is possible to disable vhosts by setting the `NO_VHOST` environment variable: +If desired, it is possible to disable vhosts by setting the environment variable `NO_VHOST=1`: ```shell dokku config:set myapp NO_VHOST=1 diff --git a/plugins/00_dokku-standard/commands b/plugins/00_dokku-standard/commands index 051956413..4e3eb5141 100755 --- a/plugins/00_dokku-standard/commands +++ b/plugins/00_dokku-standard/commands @@ -2,6 +2,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" case "$1" in build) @@ -189,9 +190,7 @@ case "$1" in SCHEME="https" fi - if [[ -f "$DOKKU_ROOT/VHOST" ]] && [[ "$NO_VHOST" != "1" ]]; then - echo "$SCHEME://$(< "$DOKKU_ROOT/VHOST")" - else + if [[ "$(is_app_vhost_enabled $APP)" == "false" ]]; then for PORT_FILE in $DOKKU_ROOT/$APP/PORT.*; do echo "http://$(< "$DOKKU_ROOT/HOSTNAME"):$(< "$PORT_FILE") (container)" done @@ -205,6 +204,8 @@ case "$1" in if [[ -n "$DOKKU_NGINX_SSL_PORT" ]]; then echo "https://$(< "$DOKKU_ROOT/HOSTNAME"):$DOKKU_NGINX_SSL_PORT (nginx-ssl)" fi + else + echo "$SCHEME://$(< "$DOKKU_ROOT/VHOST")" fi ;; diff --git a/plugins/common/functions b/plugins/common/functions index 2e6aa2891..69e4c6315 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -331,7 +331,7 @@ docker_cleanup() { docker rmi $(docker images -f 'dangling=true' -q) &> /dev/null & } -get_open_port() { +get_available_port() { while true; do local port=$(shuf -i 1025-65535 -n 1) if ! nc -z 0.0.0.0 $port; then diff --git a/plugins/config/functions b/plugins/config/functions index 6dca410bb..6e727623d 100644 --- a/plugins/config/functions +++ b/plugins/config/functions @@ -214,6 +214,7 @@ config_unset() { ENV_TEMP=$(echo -e "${ENV_TEMP}" | sed "/^export $var=/ d") config_write "$ENV_TEMP" + [[ "$var" == "NO_VHOST" ]] && config_set --no-restart $APP NO_VHOST=0 && DOKKU_CONFIG_RESTART=true done if [[ "$DOKKU_CONFIG_RESTART" == "true" ]]; then diff --git a/plugins/domains/commands b/plugins/domains/commands index 3788efb8e..f67f7648e 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/domains/functions" source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" @@ -53,7 +52,7 @@ case "$1" in fi if [[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]]; then dokku_log_info2 "unsupported vhost config found. disabling vhost support" - config_set --no-restart $APP NO_VHOST=1 + disable_app_vhost $APP --no-restart $APP else if [[ -f "$DOKKU_ROOT/VHOST" ]]; then dokku_log_info1 "Creating new $VHOST_PATH..." diff --git a/plugins/domains/functions b/plugins/domains/functions index 501f51908..4b5da1790 100755 --- a/plugins/domains/functions +++ b/plugins/domains/functions @@ -3,9 +3,9 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" get_app_domains() { - local APP=$1; local VHOST_FILE="$DOKKU_ROOT/$APP/VHOST" + local APP=$1; local APP_VHOST_FILE="$DOKKU_ROOT/$APP/VHOST" verify_app_name $APP - if [[ -f "$VHOST_FILE" ]]; then - cat "$VHOST_FILE" + if [[ -f "$APP_VHOST_FILE" ]];then + cat "$APP_VHOST_FILE" fi } diff --git a/plugins/nginx-vhosts/bind-external-ip b/plugins/nginx-vhosts/bind-external-ip index b5f5c01d5..324d82852 100755 --- a/plugins/nginx-vhosts/bind-external-ip +++ b/plugins/nginx-vhosts/bind-external-ip @@ -1,41 +1,13 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" APP="$1" -NO_VHOST=$(config_get $APP NO_VHOST || true) -RE_IPV4="([0-9]{1,3}[\.]){3}[0-9]{1,3}" - -RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 -RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 -RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: -RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) -RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) -RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 - - -# Ensure the ip address continues to the end of the line -# Fixes using a wildcard dns service such as xip.io which allows for *..xip.io -RE_IPV4="${RE_IPV4}\$" -RE_IPV6="${RE_IPV6}\$" - -[[ -f "$DOKKU_ROOT/VHOST" ]] && GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") - -if [[ -n "$NO_VHOST" ]]; then +if [[ "$(is_app_vhost_enabled $APP)" == "false" ]]; then echo true # bind to external ip. VHOST is disabled -elif [[ "$GLOBAL_VHOST" =~ $RE_IPV4 ]] || [[ "$GLOBAL_VHOST" =~ $RE_IPV6 ]]; then - echo true # bind to external ip. GLOBAL_VHOST is somehow an IPv4 or IPv6 address -elif [[ -z "$GLOBAL_VHOST" ]] && [[ ! -f "$DOKKU_ROOT/$APP/VHOST" ]]; then - echo true # bind to external ip. no GLOBAL_VHOST and no app vhost -elif [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then - echo false # bind to docker ip. this app has a vhost defined +elif [[ "$(is_global_vhost_enabled $APP)" == "false" ]] && [[ ! -f "$DOKKU_ROOT/$APP/VHOST" ]]; then + echo true # bind to external ip. no global vhost or global vhost is an ip else echo false fi diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index d90349d79..44e03a27d 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -35,12 +35,11 @@ case "$1" in verify_app_name "$2" APP="$2" - eval "$(config_export app $APP)" - if [[ -z "$NO_VHOST" ]]; then - config_set --no-restart $APP NO_NGINX=1 - config_set $APP NO_VHOST=1 - elif [[ -z "$NO_NGINX" ]]; then - config_set --no-restart $APP NO_NGINX=1 + if [[ "$(is_app_vhost_enabled $APP)" == "true" ]]; then + config_set --no-restart $APP DOKKU_NO_NGINX=1 + disable_app_vhost $APP + elif [[ "$(is_app_nginx_enabled $APP)" == "true" ]]; then + config_set --no-restart $APP DOKKU_NO_NGINX=1 nginx_build_config $APP else dokku_log_info1 "nginx is already disable for app ($APP)" @@ -52,10 +51,9 @@ case "$1" in verify_app_name "$2" APP="$2" - eval "$(config_export app $APP)" - if [[ -n "$NO_NGINX" ]]; then - config_unset --no-restart $APP NO_NGINX - unset NO_NGINX + if [[ "$(is_app_nginx_enabled $APP)" == "true" ]]; then + config_unset --no-restart $APP DOKKU_NO_NGINX + unset DOKKU_NO_NGINX nginx_build_config $APP else dokku_log_info1 "nginx is already enabled for app ($APP)" diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index 8b8979885..9221b77dc 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -5,6 +5,83 @@ source "$PLUGIN_AVAILABLE_PATH/certs/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/domains/functions" +is_app_nginx_enabled() { + local APP="$1" + verify_app_name "$APP" + + local DOKKU_NO_NGINX=$(config_get $APP DOKKU_NO_NGINX) + if [[ -z "$DOKKU_NO_NGINX" ]]; then + echo true + else + echo false + fi +} + +is_global_vhost_enabled() { + local GLOBAL_VHOST_FILE="$DOKKU_ROOT/VHOST" + local GLOBAL_VHOST_ENABLED=true + [[ -f "$GLOBAL_VHOST_FILE" ]] && local GLOBAL_VHOST=$(< "$GLOBAL_VHOST_FILE") + + local RE_IPV4="([0-9]{1,3}[\.]){3}[0-9]{1,3}" + + local RE_IPV6="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" # TEST: 1:2:3:4:5:6:7:8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,7}:|" # TEST: 1:: 1:2:3:4:5:6:7:: + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" # TEST: 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" # TEST: 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" # TEST: 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" # TEST: 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" # TEST: 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 + local RE_IPV6="${RE_IPV6}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" # TEST: 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 + local RE_IPV6="${RE_IPV6}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" # TEST: ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: + local RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: fe08::7:8%eth0 fe08::7:8%1 (link-local IPv6 addresses with zone index) + local RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) + local RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 + + + # Ensure the ip address continues to the end of the line + # Fixes using a wildcard dns service such as xip.io which allows for *..xip.io + local RE_IPV4="${RE_IPV4}\$" + local RE_IPV6="${RE_IPV6}\$" + + if [[ -z "$GLOBAL_VHOST" ]] || [[ "$GLOBAL_VHOST" =~ $RE_IPV4 ]] || [[ "$GLOBAL_VHOST" =~ $RE_IPV6 ]]; then + local GLOBAL_VHOST_ENABLED=false + fi + echo $GLOBAL_VHOST_ENABLED +} + +is_app_vhost_enabled() { + local APP=$1; local APP_VHOST_FILE="$DOKKU_ROOT/$APP/VHOST" + verify_app_name $APP + + local NO_VHOST=$(config_get $APP NO_VHOST) + local APP_VHOST_ENABLED=true + + if [[ "$NO_VHOST" == "1" ]]; then + local APP_VHOST_ENABLED=false + elif [[ -f "$DOKKU_ROOT/$APP/nginx.conf" ]] && [[ ! -f "$APP_VHOST_FILE" ]] && [[ "$NO_VHOST" != "0" ]]; then + local APP_VHOST_ENABLED=false + fi + + echo $APP_VHOST_ENABLED +} + +disable_app_vhost() { + local APP=$1; local APP_VHOST_FILE="$DOKKU_ROOT/$APP/VHOST" + verify_app_name $APP + + if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then + dokku_log_info1 "VHOST support disabled, deleting $APP/VHOST" + rm "$DOKKU_ROOT/$APP/VHOST" + fi + if [[ -f "$DOKKU_ROOT/$APP/URLS" ]]; then + dokku_log_info1 "VHOST support disabled, deleting $APP/URLS" + rm "$DOKKU_ROOT/$APP/URLS" + fi + + [[ "$2" == "--no-restart" ]] && local CONFIG_SET_ARGS=$2 + config_set $CONFIG_SET_ARGS $APP NO_VHOST=1 +} + validate_nginx() { set +e sudo /usr/sbin/nginx -t > /dev/null 2>&1 @@ -40,7 +117,7 @@ nginx_build_config() { eval "$(config_export global)" eval "$(config_export app $APP)" - if [[ ! -n "$NO_NGINX" ]]; then + if [[ ! -n "$DOKKU_NO_NGINX" ]]; then if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -z "$DOKKU_APP_LISTEN_IP" ]]; then shopt -s nullglob for DOKKU_APP_IP_FILE in $DOKKU_ROOT/$APP/IP.web.*; do @@ -63,21 +140,13 @@ nginx_build_config() { NGINX_CONF=$(mktemp -t "nginx.conf.XXXXXX") SCHEME="http" - if [[ -n "$NO_VHOST" ]]; then - if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then - dokku_log_info1 "VHOST support disabled, deleting $APP/VHOST" - rm "$DOKKU_ROOT/$APP/VHOST" - fi - if [[ -f "$DOKKU_ROOT/$APP/URLS" ]]; then - dokku_log_info1 "VHOST support disabled, deleting $APP/URLS" - rm "$DOKKU_ROOT/$APP/URLS" - fi - fi + # if the app has is not vhost enabled then, let's make sure we're cleaned up + [[ "$(is_app_vhost_enabled $APP)" == "false" ]] && disable_app_vhost $APP --no-restart if [[ -z "$DOKKU_NGINX_PORT" ]]; then - if [[ -n "$NO_VHOST" ]]; then + if [[ "$(is_app_vhost_enabled $APP)" == "false" ]]; then dokku_log_info1 "no nginx port set. setting to random open high port" - local NGINX_PORT=$(get_open_port) + local NGINX_PORT=$(get_available_port) else local NGINX_PORT=80 fi @@ -120,7 +189,7 @@ EOF SCHEME="https" [[ -z "$NGINX_TEMPLATE" ]] && NGINX_TEMPLATE="$PLUGIN_AVAILABLE_PATH/nginx-vhosts/templates/nginx.ssl.conf.template" - if [[ -z "$NO_VHOST" ]]; then + if [[ "$(is_app_vhost_enabled $APP)" == "true" ]]; then SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH || true) else SSL_VHOSTS=$(< $DOKKU_ROOT/HOSTNAME) @@ -128,9 +197,9 @@ EOF NONSSL_VHOSTS=$(egrep -v "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH 2> /dev/null || true) if [[ -z "$DOKKU_NGINX_SSL_PORT" ]]; then - if [[ -n "$NO_VHOST" ]]; then + if [[ "$(is_app_vhost_enabled $APP)" == "false" ]]; then dokku_log_info1 "no nginx ssl port set. setting to random open high port" - local NGINX_SSL_PORT=$(get_open_port) + local NGINX_SSL_PORT=$(get_available_port) else NGINX_SSL_PORT=443 fi @@ -159,7 +228,7 @@ EOF xargs -i echo "-----> Configuring {}..." <<< "$NONSSL_VHOSTS" fi eval "cat <<< \"$(< $NGINX_TEMPLATE)\" >> $NGINX_CONF" - if [[ -n "$NO_VHOST" ]] || ([[ -z "$NONSSL_VHOSTS" ]] && [[ -z "$SSL_VHOSTS" ]]); then + if [[ "$(is_app_vhost_enabled $APP)" == "false" ]] || ([[ -z "$NONSSL_VHOSTS" ]] && [[ -z "$SSL_VHOSTS" ]]); then sed --in-place -n -e '/^.*server_name.*$/!p' $NGINX_CONF fi @@ -184,12 +253,13 @@ EOF validate_nginx && restart_nginx fi - if [[ ! -n "$NO_VHOST" ]] && [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then + if [[ "$(is_app_vhost_enabled $APP)" == "true" ]]; then echo "# THIS FILE IS GENERATED BY DOKKU - DO NOT EDIT, YOUR CHANGES WILL BE OVERWRITTEN" > $URLS_PATH xargs -i echo "https://{}" <<< "${SSL_VHOSTS}" >> $URLS_PATH xargs -i echo "http://{}" <<< "${NONSSL_VHOSTS}" >> $URLS_PATH fi else + # note because this clause is long. if $DOKKU_NO_NGINX is set: dokku_log_info1 "nginx support is disabled for app ($APP)." if [[ -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then dokku_log_info1 "deleting nginx.conf" diff --git a/plugins/nginx-vhosts/post-deploy b/plugins/nginx-vhosts/post-deploy index cee12b518..7bdf10105 100755 --- a/plugins/nginx-vhosts/post-deploy +++ b/plugins/nginx-vhosts/post-deploy @@ -1,15 +1,12 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" APP="$1" if [[ -f "$DOKKU_ROOT/$APP/IP.web.1" ]] && [[ -f "$DOKKU_ROOT/$APP/PORT.web.1" ]]; then - NO_VHOST=$(config_get $APP NO_VHOST || true) - - if [[ -n "$NO_VHOST" ]]; then - dokku_log_info1 "NO_VHOST config detected" + if [[ "$(is_app_vhost_enabled $APP)" == "false" ]]; then + dokku_log_info1 "VHOST support disabled. Skipping domains setup" elif [[ ! -f "$DOKKU_ROOT/$APP/VHOST" ]]; then dokku domains:setup $APP fi diff --git a/tests/unit/core_ports.bats b/tests/unit/core_ports.bats index 79f6c1b95..426de3ea8 100644 --- a/tests/unit/core_ports.bats +++ b/tests/unit/core_ports.bats @@ -142,16 +142,6 @@ check_urls() { check_urls http://www.test.app.dokku.me } -@test "(core) dockerfile port exposure" { - deploy_app dockerfile - run bash -c "grep -A1 upstream $DOKKU_ROOT/$TEST_APP/nginx.conf | grep -q 3000" - echo "output: "$output - echo "status: "$status - assert_success - - check_urls http://${TEST_APP}.dokku.me -} - @test "(core) port exposure (xip.io style hostnames)" { echo "127.0.0.1.xip.io" > "$DOKKU_ROOT/VHOST" deploy_app @@ -164,6 +154,16 @@ check_urls() { check_urls http://my-cool-guy-test-app.127.0.0.1.xip.io } +@test "(core) dockerfile port exposure" { + deploy_app dockerfile + run bash -c "grep -A1 upstream $DOKKU_ROOT/$TEST_APP/nginx.conf | grep -q 3000" + echo "output: "$output + echo "status: "$status + assert_success + + check_urls http://${TEST_APP}.dokku.me +} + @test "(core) port exposure (dockerfile raw port)" { source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" cat< $DOCKERFILE