Files
dokku/plugins/nginx-vhosts/functions
Jose Diaz-Gonzalez a43fc39d9a Support nginx 1.9.5+
Newer versions of nginx drop spdy support in favor of http2, and thus the nginx config that we bundle with dokku causes nginx to fail to reload in certain cases. This change drops spdy support in favor of http2 for versions of nginx greater than 1.9.5.

Closes #2216
2016-06-16 17:18:43 -04:00

271 lines
10 KiB
Bash
Executable File

#!/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"
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
validate_nginx() {
declare desc="validate entire nginx config"
set +e
sudo /usr/sbin/nginx -t > /dev/null 2>&1
local exit_code=$?
set -e
if [[ "$exit_code" -ne "0" ]]; then
sudo /usr/sbin/nginx -t
exit "$exit_code"
fi
}
restart_nginx() {
declare desc="restart nginx for given distros"
case "$DOKKU_DISTRO" in
debian)
sudo /usr/sbin/invoke-rc.d nginx reload > /dev/null
;;
ubuntu)
sudo /etc/init.d/nginx reload > /dev/null
;;
opensuse)
sudo /sbin/service nginx reload > /dev/null
;;
arch)
sudo /usr/bin/systemctl reload nginx
;;
esac
}
nginx_logs() {
declare desc="display app nginx logs"
local APP="$2"; verify_app_name "$APP"
local NGINX_LOGS_TYPE=${1#nginx:}
local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-logs}
local NGINX_LOGS_PATH="/var/log/nginx/$APP-$NGINX_LOGS_TYPE.log"
if [[ $3 == "-t" ]]; then
local NGINX_LOGS_ARGS="-F"
else
local NGINX_LOGS_ARGS="-n 20"
fi
tail "$NGINX_LOGS_ARGS" "$NGINX_LOGS_PATH"
}
configure_nginx_ports() {
declare desc="configure nginx listening ports"
local APP=$1; verify_app_name "$APP"
local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")"
local DOKKU_NGINX_PORT=$(config_get "$APP" DOKKU_NGINX_PORT)
local DOKKU_NGINX_SSL_PORT=$(config_get "$APP" DOKKU_NGINX_SSL_PORT)
local IS_APP_VHOST_ENABLED="$(is_app_vhost_enabled "$APP")"
if [[ -z "$DOKKU_NGINX_PORT" ]]; then
if [[ -z "$RAW_TCP_PORTS" ]]; then
if [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
dokku_log_info1 "no nginx port set. setting to random open high port"
local NGINX_PORT=$(get_available_port)
else
local NGINX_PORT=80
fi
fi
if [[ -n "$NGINX_PORT" ]]; then
config_set --no-restart "$APP" DOKKU_NGINX_PORT="${NGINX_PORT}"
fi
fi
if (is_ssl_enabled "$APP") && [[ -z "$DOKKU_NGINX_SSL_PORT" ]] && [[ -z "$RAW_TCP_PORTS" ]]; then
if [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
dokku_log_info1 "no nginx ssl port set. setting to random open high port"
local NGINX_SSL_PORT=$(get_available_port)
else
local NGINX_SSL_PORT=443
fi
config_set --no-restart "$APP" DOKKU_NGINX_SSL_PORT="${NGINX_SSL_PORT}"
fi
}
validate_ssl_domains() {
declare desc="check configured domains against SSL cert contents and show warning if mismatched"
local APP=$1; verify_app_name "$APP"
local SSL_HOSTNAME=$(get_ssl_hostnames "$APP")
local SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g')
local domain
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
}
get_custom_nginx_template() {
declare desc="attempts to copy custom nginx template from app image"
local APP="$1"; verify_app_name "$APP"
local DESTINATION="$2"
local IMAGE_TAG="$(get_running_image_tag "$APP")"
local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
local NGINX_TEMPLATE_NAME="nginx.conf.sigil"
copy_from_image "$IMAGE" "$NGINX_TEMPLATE_NAME" "$DESTINATION" 2>/dev/null || true
}
is_spdy_enabled() {
declare desc="detects whether the installed nginx version has spdy or http2 support"
local NGINX_VERSION="$1"
local MAJOR_VERSION MINOR_VERSION PATCH_VERSION
local HAS_SUPPORT=true
if ! which nginx > /dev/null 2>&1; then
echo $HAS_SUPPORT
return
fi
MAJOR_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[1]}')
MINOR_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[2]}')
PATCH_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[3]}')
if [[ "$MAJOR_VERSION" -ge "2" ]]; then
HAS_SUPPORT=false
elif [[ "$MAJOR_VERSION" -eq "1" ]]; then
if [[ "$MINOR_VERSION" -ge "10" ]]; then
HAS_SUPPORT=false
elif [[ "$MINOR_VERSION" -ge "9" ]] && [[ "$PATCH_VERSION" -ge "5" ]]; then
HAS_SUPPORT=false
fi
fi
echo $HAS_SUPPORT
}
nginx_build_config() {
declare desc="build nginx config to proxy app containers using sigil"
local APP="$1"; verify_app_name "$APP"
local DOKKU_APP_LISTEN_PORT="$2"; local DOKKU_APP_LISTEN_IP="$3"
local VHOST_PATH="$DOKKU_ROOT/$APP/VHOST"; local URLS_PATH="$DOKKU_ROOT/$APP/URLS"
local NGINX_TEMPLATE_NAME="nginx.conf.sigil"
local DEFAULT_NGINX_TEMPLATE="$PLUGIN_AVAILABLE_PATH/nginx-vhosts/templates/$NGINX_TEMPLATE_NAME"
local NGINX_TEMPLATE="$DEFAULT_NGINX_TEMPLATE"; local SCHEME=http
local NGINX_TEMPLATE_SOURCE="built-in"; local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls"
local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")"
local DOKKU_DISABLE_PROXY=$(config_get "$APP" DOKKU_DISABLE_PROXY)
local IS_APP_VHOST_ENABLED=$(is_app_vhost_enabled "$APP")
if [[ -z "$DOKKU_DISABLE_PROXY" ]]; then
if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -z "$DOKKU_APP_LISTEN_IP" ]]; then
shopt -s nullglob
local DOKKU_APP_IP_FILE
for DOKKU_APP_IP_FILE in $DOKKU_ROOT/$APP/IP.web.*; do
local DOKKU_APP_PORT_FILE="${DOKKU_APP_IP_FILE//IP/PORT}"
local DOKKU_APP_LISTENER_IP=$(< "$DOKKU_APP_IP_FILE")
local DOKKU_APP_LISTENER_PORT=$(< "$DOKKU_APP_PORT_FILE")
if [[ -z "$RAW_TCP_PORTS" ]]; then
local DOKKU_APP_LISTENERS+=" $DOKKU_APP_LISTENER_IP:$DOKKU_APP_LISTENER_PORT "
else
local DOKKU_APP_LISTENERS+=" $DOKKU_APP_LISTENER_IP "
fi
local DOKKU_APP_LISTENERS=$(echo "$DOKKU_APP_LISTENERS" | xargs)
done
shopt -u nullglob
elif [[ -n "$DOKKU_APP_LISTEN_PORT" ]] && [[ -n "$DOKKU_APP_LISTEN_IP" ]]; then
local PASSED_LISTEN_IP_PORT=true
fi
local NGINX_BUILD_CONFIG_TMP_WORK_DIR=$(mktemp -d /tmp/dokku_nginx_template.XXXXX)
local NGINX_CONF=$(mktemp --tmpdir="${NGINX_BUILD_CONFIG_TMP_WORK_DIR}" "nginx.conf.XXXXXX")
local CUSTOM_NGINX_TEMPLATE="$NGINX_BUILD_CONFIG_TMP_WORK_DIR/$NGINX_TEMPLATE_NAME"
# shellcheck disable=SC2086
trap 'rm -rf $NGINX_CONF $NGINX_BUILD_CONFIG_TMP_WORK_DIR > /dev/null' RETURN INT TERM EXIT
get_custom_nginx_template "$APP" "$CUSTOM_NGINX_TEMPLATE"
if [[ -f "$CUSTOM_NGINX_TEMPLATE" ]]; then
dokku_log_info1 'Overriding default nginx.conf with detected nginx.conf.sigil'
local NGINX_TEMPLATE="$CUSTOM_NGINX_TEMPLATE"
local NGINX_TEMPLATE_SOURCE="app-supplied"
fi
# setup nginx listen ports
configure_nginx_ports "$APP"
local NGINX_PORT=$(config_get "$APP" DOKKU_NGINX_PORT)
local NGINX_SSL_PORT=$(config_get "$APP" DOKKU_NGINX_SSL_PORT)
local NONSSL_VHOSTS=$(get_app_domains "$APP")
local NOSSL_SERVER_NAME=$(echo "$NONSSL_VHOSTS" | xargs)
if is_ssl_enabled "$APP"; then
local SSL_INUSE=true; local SCHEME=https
validate_ssl_domains "$APP"
local SSL_HOSTNAME=$(get_ssl_hostnames "$APP")
local SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g')
if [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then
local SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$" "$VHOST_PATH" || true)
else
local SSL_VHOSTS=$(< "$DOKKU_ROOT/HOSTNAME")
fi
local SSL_SERVER_NAME=$(echo "$SSL_VHOSTS" | xargs)
fi
local NGINX_VERSION="$(nginx -v 2>&1 | cut -d'/' -f 2)"
local SPDY_SUPPORTED="$(is_spdy_enabled "$NGINX_VERSION")"
eval "$(config_export app "$APP")"
local SIGIL_PARAMS=(-f $NGINX_TEMPLATE APP="$APP" DOKKU_ROOT="$DOKKU_ROOT"
NOSSL_SERVER_NAME="$NOSSL_SERVER_NAME"
DOKKU_APP_LISTENERS="$DOKKU_APP_LISTENERS"
PASSED_LISTEN_IP_PORT="$PASSED_LISTEN_IP_PORT"
SPDY_SUPPORTED="$SPDY_SUPPORTED"
DOKKU_APP_LISTEN_PORT="$DOKKU_APP_LISTEN_PORT" DOKKU_APP_LISTEN_IP="$DOKKU_APP_LISTEN_IP"
APP_SSL_PATH="$APP_SSL_PATH" SSL_INUSE="$SSL_INUSE" SSL_SERVER_NAME="$SSL_SERVER_NAME"
NGINX_PORT="$NGINX_PORT" NGINX_SSL_PORT="$NGINX_SSL_PORT" RAW_TCP_PORTS="$RAW_TCP_PORTS")
# execute sigil template processing
xargs -i echo "-----> Configuring {}...(using $NGINX_TEMPLATE_SOURCE template)" <<< "$(echo "${SSL_VHOSTS}" "${NONSSL_VHOSTS}" | tr ' ' '\n' | sort -u)"
# echo "sigil ${SIGIL_PARAMS[@]}"
sigil "${SIGIL_PARAMS[@]}" > "$NGINX_CONF"
if is_deployed "$APP"; then
dokku_log_info1 "Creating $SCHEME nginx.conf"
mv "$NGINX_CONF" "$DOKKU_ROOT/$APP/nginx.conf"
else
dokku_log_info1 "App $APP has not been deployed. Skipping nginx config creation"
rm -f "$NGINX_CONF"
fi
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 ([[ -n "$NONSSL_VHOSTS" ]] || [[ -n "$SSL_VHOSTS" ]]) && [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then
echo "# THIS FILE IS GENERATED BY DOKKU - DO NOT EDIT, YOUR CHANGES WILL BE OVERWRITTEN" > "$URLS_PATH"
xargs -i echo "$SCHEME://{}" <<< "$(echo "${SSL_VHOSTS}" "${NONSSL_VHOSTS}" | tr ' ' '\n' | sort -u)" >> "$URLS_PATH"
fi
else
# note because this clause is long. if $DOKKU_DISABLE_PROXY 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"
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
}