diff --git a/docs/nginx.md b/docs/nginx.md index d309e2298..1f2688b97 100644 --- a/docs/nginx.md +++ b/docs/nginx.md @@ -141,7 +141,7 @@ dokku domains:remove myapp example.com > New as of 0.3.13 -The deployed docker container running your app's web process will bind to either the internal docker network interface (i.e. `docker inspect --format '{{ .NetworkSettings.IPAddress }}' $CONTAINER_ID`) or an external interface (i.e. 0.0.0.0) depending on dokku's VHOST configuration. Dokku will attempt to bind to the internal docker network interface unless you specifically set NO_VHOST for the given app or your dokku installation is not setup to use VHOSTS (i.e. $DOKKU_ROOT/VHOST or $DOKKU_ROOT/HOSTNAME is set to an IPv4 or IPv6 address) +The deployed docker container running your app's web process will bind to either the internal docker network interface (i.e. `docker inspect --format '{{ .NetworkSettings.IPAddress }}' $CONTAINER_ID`) or an external interface (i.e. 0.0.0.0) depending on dokku's VHOST configuration. Dokku will attempt to bind to the internal docker network interface unless you specifically set NO_VHOST for the given app or your dokku installation is not setup to use VHOSTS (i.e. $DOKKU_ROOT/VHOST is missing or $DOKKU_ROOT/HOSTNAME is set to an IPv4 or IPv6 address) ```shell # container bound to docker interface diff --git a/plugins/domains/commands b/plugins/domains/commands index 9ae7bec38..e3a9825f6 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -16,6 +16,19 @@ 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 +domains_restart_app() { + APP="$1"; + + if [[ -f "$DOKKU_ROOT/$APP/CONTAINER" ]]; then + echo "-----> Releasing $APP ..." + dokku release $APP + echo "-----> Release complete!" + echo "-----> Deploying $APP ..." + dokku deploy $APP + echo "-----> Deploy complete!" + fi +} + case "$1" in domains) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 @@ -39,21 +52,23 @@ case "$1" in VHOST=$(< "$DOKKU_ROOT/HOSTNAME") fi if [[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]];then - echo "ip found as hostname. disabling vhost support" + echo "unsupported vhost config found. disabling vhost support" [[ ! $(grep -q NO_VHOST "$DOKKU_ROOT/$APP/ENV") ]] && echo "export NO_VHOST='1'" >> "$DOKKU_ROOT/$APP/ENV" else - echo "-----> Creating new $VHOST_PATH..." - SUBDOMAIN=${APP/%\.${VHOST}/} - hostname=$(: | pluginhook nginx-hostname $APP $SUBDOMAIN $VHOST) - if [[ ! -n $hostname ]]; then - if [[ "$APP" == *.* ]] && [[ "$SUBDOMAIN" == "$APP" ]]; then - hostname="${APP/\//-}" - else - hostname="${APP/\//-}.$VHOST" + if [[ -f "$DOKKU_ROOT/VHOST" ]]; then + echo "-----> Creating new $VHOST_PATH..." + SUBDOMAIN=${APP/%\.${VHOST}/} + hostname=$(: | pluginhook nginx-hostname $APP $SUBDOMAIN $VHOST) + if [[ ! -n $hostname ]]; then + if [[ "$APP" == *.* ]] && [[ "$SUBDOMAIN" == "$APP" ]]; then + hostname="${APP/\//-}" + else + hostname="${APP/\//-}.$VHOST" + fi fi - fi - echo "$hostname" > $VHOST_PATH + echo "$hostname" > $VHOST_PATH + fi fi fi ;; @@ -76,6 +91,8 @@ case "$1" in dokku domains:setup $APP echo "$3" >> "$DOKKU_ROOT/$APP/VHOST" + # we need to restart the app to make sure we're binding to the appropriate network interface + domains_restart_app $APP pluginhook post-domains-update $APP echo "-----> Added $3 to $APP" diff --git a/plugins/nginx-vhosts/bind-external-ip b/plugins/nginx-vhosts/bind-external-ip index 636bc894c..d4582b3cd 100755 --- a/plugins/nginx-vhosts/bind-external-ip +++ b/plugins/nginx-vhosts/bind-external-ip @@ -19,16 +19,14 @@ 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 -if [[ -f "$DOKKU_ROOT/VHOST" ]];then - GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") -else - GLOBAL_VHOST=$(< "$DOKKU_ROOT/HOSTNAME") -fi +[[ -f "$DOKKU_ROOT/VHOST" ]] && GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") if [[ -n "$NO_VHOST" ]]; then - echo true # bind to external ip. VHOST is disabled for this app + 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 else diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index 13f00db10..099b38cf4 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -29,7 +29,7 @@ case "$1" in [[ -f "$DOKKU_ROOT/$APP/ENV" ]] && source $DOKKU_ROOT/$APP/ENV - if [[ ! -n "$NO_VHOST" ]]; then + if [[ ! -n "$NO_VHOST" ]] && [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then NONSSL_VHOSTS=$(cat $VHOST_PATH) if [[ -e "$SSL/server.crt" ]] && [[ -e "$SSL/server.key" ]]; then SSL_INUSE="$SSL" @@ -86,14 +86,14 @@ EOF fi else if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then - echo "-----> NO_VHOST set, deleting $APP/VHOST" + echo "-----> VHOST support disabled, deleting $APP/VHOST" rm "$DOKKU_ROOT/$APP/VHOST" fi if [[ -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then - echo "-----> NO_VHOST set, deleting nginx.conf" + echo "-----> VHOST support disabled, deleting nginx.conf" rm "$DOKKU_ROOT/$APP/nginx.conf" - echo "-----> NO_VHOST set, reloading nginx after nginx.conf deletion" + echo "-----> VHOST support disabled, reloading nginx after nginx.conf deletion" restart_nginx fi fi diff --git a/tests/unit/nginx-vhosts.bats b/tests/unit/nginx-vhosts.bats index db00a7ce5..bd1b1f285 100644 --- a/tests/unit/nginx-vhosts.bats +++ b/tests/unit/nginx-vhosts.bats @@ -3,11 +3,15 @@ load test_helper setup() { + [[ -f "$DOKKU_ROOT/VHOST" ]] && cp -f "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak" + [[ -f "$DOKKU_ROOT/HOSTNAME" ]] && cp -f "$DOKKU_ROOT/HOSTNAME" "$DOKKU_ROOT/HOSTNAME.bak" create_app } teardown() { destroy_app + [[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" + [[ -f "$DOKKU_ROOT/HOSTNAME.bak" ]] && mv "$DOKKU_ROOT/HOSTNAME.bak" "$DOKKU_ROOT/HOSTNAME" } @test "nginx (no server tokens)" { @@ -26,3 +30,19 @@ teardown() { echo "status: "$status assert_output "node-js-app.dokku.me" } + +@test "nginx:build-config (no global VHOST and domains:add)" { + destroy_app + rm "$DOKKU_ROOT/VHOST" + create_app + run dokku domains:add $TEST_APP www.test.app.dokku.me + echo "output: "$output + echo "status: "$status + assert_success + deploy_app + sleep 5 # wait for nginx to reload + run bash -c "response=\"$(curl -s -S www.test.app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" + echo "output: "$output + echo "status: "$status + assert_success +} diff --git a/tests/unit/ports.bats b/tests/unit/ports.bats index 9e641eed3..bace5c786 100644 --- a/tests/unit/ports.bats +++ b/tests/unit/ports.bats @@ -5,7 +5,6 @@ load test_helper setup() { [[ -f "$DOKKU_ROOT/VHOST" ]] && cp -f "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak" [[ -f "$DOKKU_ROOT/HOSTNAME" ]] && cp -f "$DOKKU_ROOT/HOSTNAME" "$DOKKU_ROOT/HOSTNAME.bak" - } teardown() { @@ -32,7 +31,7 @@ teardown() { run bash -c "docker port $CONTAINER_ID | sed 's/[0-9.]*://' | egrep '[0-9]*'" echo "output: "$output echo "status: "$status - assert_failure + assert_success } @test "port exposure (with NO_VHOST set)" { @@ -67,14 +66,43 @@ teardown() { assert_success } -@test "port exposure (domains:add)" { +@test "port exposure (pre-deploy domains:add)" { create_app run dokku domains:add $TEST_APP www.test.app.dokku.me echo "output: "$output echo "status: "$status assert_success + deploy_app sleep 5 # wait for nginx to reload + + CONTAINER_ID=$(docker ps --no-trunc| grep dokku/$TEST_APP | grep "start web" | awk '{ print $1 }') + run bash -c "docker port $CONTAINER_ID | sed 's/[0-9.]*://' | egrep '[0-9]*'" + echo "output: "$output + echo "status: "$status + assert_failure + + run bash -c "response=\"$(curl -s -S www.test.app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" + echo "output: "$output + echo "status: "$status + assert_success +} + +@test "port exposure (no global VHOST and domains:add post deploy)" { + rm "$DOKKU_ROOT/VHOST" + deploy_app + + run dokku domains:add $TEST_APP www.test.app.dokku.me + echo "output: "$output + echo "status: "$status + assert_success + + CONTAINER_ID=$(docker ps --no-trunc| grep dokku/$TEST_APP | grep "start web" | awk '{ print $1 }') + run bash -c "docker port $CONTAINER_ID | sed 's/[0-9.]*://' | egrep '[0-9]*'" + echo "output: "$output + echo "status: "$status + assert_failure + run bash -c "response=\"$(curl -s -S www.test.app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" echo "output: "$output echo "status: "$status