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
271 lines
10 KiB
Bash
Executable File
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
|
|
}
|