diff --git a/docker/etc/my_init.d/10_dokku_init b/docker/etc/my_init.d/10_dokku_init index 7caff134b..d60ad507c 100755 --- a/docker/etc/my_init.d/10_dokku_init +++ b/docker/etc/my_init.d/10_dokku_init @@ -13,6 +13,8 @@ log-fail() { } main() { + local NGINX_ROOT + if [[ ! -d /mnt/dokku ]]; then log-info "Creating missing /mnt/dokku" mkdir -p /mnt/dokku @@ -49,14 +51,23 @@ main() { echo "export DOCKER_BIN=/usr/local/bin/docker" >"/home/dokku/.dokkurc/DOCKER_BIN" fi - if [[ ! -f /mnt/dokku/etc/nginx/dhparam.pem ]]; then - mkdir -p /mnt/dokku/etc/nginx - openssl dhparam -out /mnt/dokku/etc/nginx/dhparam.pem 2048 + NGINX_ROOT="/etc/nginx" + if [[ -x /usr/bin/openresty ]]; then + NGINX_ROOT="/usr/local/openresty/nginx/conf" + rm -rf /etc/runit/runsvdir/default/nginx + else + rm -rf /etc/runit/runsvdir/default/openresty fi - cp -f /mnt/dokku/etc/nginx/dhparam.pem /etc/nginx/dhparam.pem - chown root:root /etc/nginx/dhparam.pem - chown root:root /etc/nginx/conf.d + if [[ ! -f "/mnt/dokku${NGINX_ROOT}/dhparam.pem" ]]; then + mkdir -p "/mnt/dokku${NGINX_ROOT}" + openssl dhparam -out "/mnt/dokku${NGINX_ROOT}/dhparam.pem" 2048 + fi + + mkdir -p "${NGINX_ROOT}/conf.d" + cp -f "/mnt/dokku${NGINX_ROOT}/dhparam.pem" "${NGINX_ROOT}/dhparam.pem" + chown root:root "${NGINX_ROOT}/dhparam.pem" + chown root:root "${NGINX_ROOT}/conf.d" } main "$@" diff --git a/docker/etc/runit/runsvdir/default/openresty/run b/docker/etc/runit/runsvdir/default/openresty/run new file mode 100755 index 000000000..66cd2211e --- /dev/null +++ b/docker/etc/runit/runsvdir/default/openresty/run @@ -0,0 +1,7 @@ +#!/bin/bash + +exec >>/var/log/services/openresty +exec 2>&1 + +echo "Running openresty" +exec /usr/bin/openresty -c /usr/local/openresty/nginx/conf/nginx.conf -g "daemon off;" diff --git a/docker/usr/local/openresty/nginx/conf/nginx.conf b/docker/usr/local/openresty/nginx/conf/nginx.conf new file mode 100644 index 000000000..d465e846b --- /dev/null +++ b/docker/usr/local/openresty/nginx/conf/nginx.conf @@ -0,0 +1,30 @@ +user www-data; +worker_processes auto; +pid /run/openresty.pid; +include /usr/local/openresty/nginx/conf/modules-enabled/*.conf; + +events { + worker_connections 768; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /usr/local/openresty/nginx/conf/mime.types; + default_type application/octet-stream; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + + access_log /var/log/openresty/access.log; + error_log /var/log/openresty/error.log; + + gzip on; + + include /usr/local/openresty/nginx/conf/conf.d/*.conf; + include /usr/local/openresty/nginx/conf/sites-enabled/*; +} diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index 03ab8637c..1aa1562bc 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -11,18 +11,7 @@ source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/internal-functions" get_nginx_location() { declare desc="check that nginx is at the expected location and return it" - local NGINX_LOCATION - - NGINX_LOCATION=$(which nginx 2>/dev/null) - if [[ -z "$NGINX_LOCATION" ]]; then - NGINX_LOCATION="/usr/sbin/nginx" - fi - - if [[ ! -x "$NGINX_LOCATION" ]]; then - dokku_log_fail "Could not find nginx binary in \$PATH or at '${NGINX_LOCATION}'." - fi - - echo "$NGINX_LOCATION" + fn-nginx-vhosts-nginx-location } validate_nginx() { @@ -69,32 +58,18 @@ validate_nginx() { 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 | centos | rhel) - sudo /usr/bin/systemctl reload nginx - ;; - esac + fn-nginx-vhosts-nginx-init-cmd "reload" } nginx_logs() { declare desc="display app nginx logs" - local APP="$2" + declare NGINX_LOGS_TYPE="${1#nginx:}" APP="$2" + local NGINX_LOG_ROOT="/var/log/nginx" verify_app_name "$APP" - local NGINX_LOGS_TYPE=${1#nginx:} + + fn-nginx-vhosts-uses-openresty && NGINX_LOG_ROOT="/var/log/openresty" local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-logs} - local NGINX_LOGS_PATH="/var/log/nginx/$APP-$NGINX_LOGS_TYPE.log" + local NGINX_LOGS_PATH="$NGINX_LOG_ROOT/$APP-$NGINX_LOGS_TYPE.log" if [[ $3 == "-t" ]]; then local NGINX_LOGS_ARGS="-F" @@ -372,6 +347,9 @@ nginx_build_config() { PROXY_PORT_MAP=$(echo "$PROXY_PORT_MAP" | xargs) # trailing spaces mess up default template + local NGINX_LOG_ROOT="/var/log/nginx" + fn-nginx-vhosts-uses-openresty && NGINX_LOG_ROOT="/var/log/openresty" + eval "$(config_export app "$APP")" local SIGIL_PARAMS=(-f "$NGINX_TEMPLATE" APP="$APP" DOKKU_ROOT="$DOKKU_ROOT" NOSSL_SERVER_NAME="$NOSSL_SERVER_NAME" @@ -380,6 +358,7 @@ nginx_build_config() { PASSED_LISTEN_IP_PORT="$PASSED_LISTEN_IP_PORT" SPDY_SUPPORTED="$SPDY_SUPPORTED" HTTP2_SUPPORTED="$HTTP2_SUPPORTED" + NGINX_LOG_ROOT="$NGINX_LOG_ROOT" HTTP2_PUSH_SUPPORTED="$HTTP2_PUSH_SUPPORTED" GRPC_SUPPORTED="$GRPC_SUPPORTED" DOKKU_APP_LISTEN_PORT="$DOKKU_APP_LISTEN_PORT" DOKKU_APP_LISTEN_IP="$DOKKU_APP_LISTEN_IP" @@ -403,7 +382,7 @@ nginx_build_config() { plugn trigger nginx-pre-reload "$APP" "$DOKKU_APP_LISTEN_PORT" "$DOKKU_APP_LISTEN_IP" dokku_log_verbose "Reloading nginx" - validate_nginx && restart_nginx + validate_nginx && restart_nginx >/dev/null fi if ([[ -n "$NONSSL_VHOSTS" ]] || [[ -n "$SSL_VHOSTS" ]]) && [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then @@ -419,7 +398,7 @@ nginx_build_config() { if (is_deployed "$APP"); then dokku_log_info1 "reloading nginx after nginx.conf deletion" - validate_nginx && restart_nginx + validate_nginx && restart_nginx >/dev/null fi fi fi diff --git a/plugins/nginx-vhosts/install b/plugins/nginx-vhosts/install index 02cdc8c25..6ff611a04 100755 --- a/plugins/nginx-vhosts/install +++ b/plugins/nginx-vhosts/install @@ -3,41 +3,58 @@ 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/internal-functions" + +NGINX_BIN="$(fn-nginx-vhosts-nginx-location)" +NGINX_ROOT="/etc/nginx" +NGINX_LOG_ROOT="/var/log/nginx" +NGINX_INIT_NAME="nginx" +NGINX_SUDOERS_FILE="/etc/sudoers.d/dokku-nginx" +if fn-nginx-vhosts-uses-openresty; then + NGINX_ROOT="/usr/local/openresty/nginx/conf" + NGINX_LOG_ROOT="/var/log/openresty" + NGINX_INIT_NAME="openresty" + NGINX_SUDOERS_FILE="/etc/sudoers.d/dokku-openresty" +fi case "$DOKKU_DISTRO" in debian) - echo "%dokku ALL=(ALL) NOPASSWD:/usr/sbin/invoke-rc.d nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx + echo "%dokku ALL=(ALL) NOPASSWD:/usr/sbin/invoke-rc.d $NGINX_INIT_NAME reload, $NGINX_BIN -t, ${NGINX_BIN} -t -c *" >"$NGINX_SUDOERS_FILE" ;; ubuntu) - echo "%dokku ALL=(ALL) NOPASSWD:/etc/init.d/nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx + if [[ -x /usr/bin/sv ]]; then + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/sv reload $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + else + echo "%dokku ALL=(ALL) NOPASSWD:/etc/init.d/$NGINX_INIT_NAME reload, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + fi ;; opensuse) - echo "%dokku ALL=(ALL) NOPASSWD:/sbin/service nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx + echo "%dokku ALL=(ALL) NOPASSWD:/sbin/service $NGINX_INIT_NAME reload, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" ;; arch) - echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload nginx, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" ;; centos | rhel) - echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload nginx, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx - echo "Defaults:dokku !requiretty" >>/etc/sudoers.d/dokku-nginx + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + echo "Defaults:dokku !requiretty" >>"$NGINX_SUDOERS_FILE" ;; esac -chmod 0440 /etc/sudoers.d/dokku-nginx +chmod 0440 "$NGINX_SUDOERS_FILE" # if dhparam.pem has not been created, create it the first time -if [[ ! -f /etc/nginx/dhparam.pem ]]; then - openssl dhparam -out /etc/nginx/dhparam.pem 2048 +if [[ ! -f "$NGINX_ROOT/dhparam.pem" ]]; then + openssl dhparam -out "$NGINX_ROOT/dhparam.pem" 2048 fi -mkdir -p /etc/nginx/conf.d -chown root:root /etc/nginx/dhparam.pem -chown root:root /etc/nginx/conf.d -cat </etc/nginx/conf.d/dokku.conf +mkdir -p "$NGINX_ROOT/conf.d" +chown root:root "$NGINX_ROOT/dhparam.pem" +chown root:root "$NGINX_ROOT/conf.d" +cat <"$NGINX_ROOT/conf.d/dokku.conf" include $DOKKU_ROOT/*/nginx.conf; server_tokens off; @@ -47,19 +64,20 @@ ssl_session_cache shared:SSL:20m; ssl_session_timeout 1d; ssl_session_tickets off; -ssl_dhparam /etc/nginx/dhparam.pem; +ssl_dhparam $NGINX_ROOT/dhparam.pem; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; EOF # allow users to override their server_names_hash_bucket_size -if [[ ! -f /etc/nginx/conf.d/server_names_hash_bucket_size.conf ]]; then - echo 'server_names_hash_bucket_size 512;' >|/etc/nginx/conf.d/server_names_hash_bucket_size.conf +if [[ ! -f "$NGINX_ROOT/conf.d/server_names_hash_bucket_size.conf" ]]; then + echo 'server_names_hash_bucket_size 512;' >|"$NGINX_ROOT/conf.d/server_names_hash_bucket_size.conf" fi # revert dokku group changes +mkdir -p "$NGINX_LOG_ROOT" gpasswd -a dokku adm -chgrp --quiet -R adm /var/log/nginx +chgrp --quiet -R adm "$NGINX_LOG_ROOT" gpasswd -M "$(egrep ^dokku: /etc/group | awk -F ":" '{ print $4 }')" dokku [[ -f /etc/logrotate.d/nginx ]] && sed -i -e 's/create 0640 www-data dokku/create 0640 www-data adm/g' /etc/logrotate.d/nginx @@ -93,24 +111,9 @@ for app in $(dokku_apps); do fi done -case "$DOKKU_DISTRO" in - debian) - NGINX_INIT="/usr/sbin/invoke-rc.d" - "$NGINX_INIT" nginx start || "$NGINX_INIT" nginx reload - ;; - - ubuntu) - NGINX_INIT="/etc/init.d/nginx" - "$NGINX_INIT" start || "$NGINX_INIT" reload - ;; - - opensuse) - NGINX_INIT="/sbin/service" - "$NGINX_INIT" nginx start || "$NGINX_INIT" nginx reload - ;; - - arch | centos | rhel) - NGINX_INIT="/usr/bin/systemctl" - "$NGINX_INIT" start nginx || "$NGINX_INIT" reload nginx - ;; -esac +# avoid failing runit init calls on install +# the runit binaries are not yet available during dockerfile building +# and therefore both these calls will fail +if [[ ! -x /usr/bin/sv ]]; then + fn-nginx-vhosts-nginx-init-cmd start || fn-nginx-vhosts-nginx-init-cmd reload +fi diff --git a/plugins/nginx-vhosts/internal-functions b/plugins/nginx-vhosts/internal-functions index 576db3504..451f7bbe0 100755 --- a/plugins/nginx-vhosts/internal-functions +++ b/plugins/nginx-vhosts/internal-functions @@ -1,6 +1,72 @@ #!/usr/bin/env bash set -eo pipefail [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +fn-nginx-vhosts-uses-openresty() { + declare desc="returns whether openresty is in use or not" + + if [[ -x /usr/bin/openresty ]]; then + return + fi + + return 1 +} + +fn-nginx-vhosts-nginx-location() { + declare desc="check that nginx is at the expected location and return it" + local NGINX_LOCATION + + NGINX_LOCATION=$(which nginx 2>/dev/null) + if [[ -z "$NGINX_LOCATION" ]]; then + NGINX_LOCATION="/usr/sbin/nginx" + fi + + if fn-nginx-vhosts-uses-openresty; then + NGINX_LOCATION="/usr/bin/openresty" + fi + + if [[ ! -x "$NGINX_LOCATION" ]]; then + dokku_log_fail "Could not find nginx binary in \$PATH or at '${NGINX_LOCATION}'." + fi + + echo "$NGINX_LOCATION" +} + +fn-nginx-vhosts-nginx-init-cmd() { + declare desc="start nginx for given distros" + declare CMD="$1" + local NGINX_INIT_NAME + + + NGINX_INIT_NAME=nginx + if fn-nginx-vhosts-uses-openresty; then + NGINX_INIT_NAME=openresty + fi + + case "$DOKKU_DISTRO" in + debian) + sudo /usr/sbin/invoke-rc.d "$NGINX_INIT_NAME" "$CMD" + ;; + + ubuntu) + # support docker-based installations + if [[ -x /usr/bin/sv ]]; then + sudo /usr/bin/sv "$CMD" "$NGINX_INIT_NAME" + else + sudo "/etc/init.d/$NGINX_INIT_NAME" "$CMD" + fi + ;; + + opensuse) + sudo /sbin/service "$NGINX_INIT_NAME" "$CMD" + ;; + + arch | centos | rhel) + sudo /usr/bin/systemctl "$CMD" "$NGINX_INIT_NAME" + ;; + esac +} nginx_vhosts_validate_single_func() { declare APP="$1" FLAG="$2" diff --git a/plugins/nginx-vhosts/post-delete b/plugins/nginx-vhosts/post-delete index 115723393..f857dc99c 100755 --- a/plugins/nginx-vhosts/post-delete +++ b/plugins/nginx-vhosts/post-delete @@ -3,4 +3,4 @@ set -eo pipefail [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" -restart_nginx "$@" +restart_nginx "$@" >/dev/null diff --git a/plugins/nginx-vhosts/templates/nginx.conf.sigil b/plugins/nginx-vhosts/templates/nginx.conf.sigil index 04db4383c..7a0c04b9d 100644 --- a/plugins/nginx-vhosts/templates/nginx.conf.sigil +++ b/plugins/nginx-vhosts/templates/nginx.conf.sigil @@ -9,8 +9,8 @@ server { listen [::]:{{ $listen_port }}; listen {{ $listen_port }}; {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} - access_log /var/log/nginx/{{ $.APP }}-access.log; - error_log /var/log/nginx/{{ $.APP }}-error.log; + access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log; + error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log; {{ if (and (eq $listen_port "80") ($.SSL_INUSE)) }} return 301 https://$host:{{ $.PROXY_SSL_PORT }}$request_uri; {{ else }} @@ -60,8 +60,8 @@ server { listen {{ $listen_port }} ssl {{ if eq $.HTTP2_SUPPORTED "true" }}http2{{ else if eq $.SPDY_SUPPORTED "true" }}spdy{{ end }}; {{ if $.SSL_SERVER_NAME }}server_name {{ $.SSL_SERVER_NAME }}; {{ end }} {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} - access_log /var/log/nginx/{{ $.APP }}-access.log; - error_log /var/log/nginx/{{ $.APP }}-error.log; + access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log; + error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log; ssl_certificate {{ $.APP_SSL_PATH }}/server.crt; ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key; @@ -123,8 +123,8 @@ server { listen [::]:{{ $listen_port }} http2; listen {{ $listen_port }} http2; {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} - access_log /var/log/nginx/{{ $.APP }}-access.log; - error_log /var/log/nginx/{{ $.APP }}-error.log; + access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log; + error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log; location / { grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }}; } @@ -137,8 +137,8 @@ server { listen [::]:{{ $listen_port }} ssl http2; listen {{ $listen_port }} ssl http2; {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} - access_log /var/log/nginx/{{ $.APP }}-access.log; - error_log /var/log/nginx/{{ $.APP }}-error.log; + access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log; + error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log; ssl_certificate {{ $.APP_SSL_PATH }}/server.crt; ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;