diff --git a/docs/configuration/domains.md b/docs/configuration/domains.md index de066357c..a6d65c51d 100644 --- a/docs/configuration/domains.md +++ b/docs/configuration/domains.md @@ -4,12 +4,13 @@ ``` domains:add DOMAIN # Add a domain to app +domains:add-global # Add global domain name domains [] # List domains domains:clear # Clear all domains for app domains:disable # Disable VHOST support domains:enable # Enable VHOST support domains:remove DOMAIN # Remove a domain from app -domains:set-global # Set global domain name +domains:remove-global # Remove global domain name ``` > Adding a domain before deploying an application will result in port mappings being set. This may cause issues for applications that use non-standard ports, as those will not be automatically detected. Please refer to the [proxy documentation](/dokku/advanced-usage/proxy-management/) for information as to how to reconfigure the mappings. @@ -22,7 +23,7 @@ Applications typically have the following structure for their hostname: scheme://subdomain.domain.tld ``` -The `subdomain` is inferred from the pushed application name, while the `domain.tld` is set during initial configuration and stored in the `$DOKKU_ROOT/VHOST` file. It can then be modified with `dokku domains:set-global`. This value is used as a default TLD for all applications on a host. +The `subdomain` is inferred from the pushed application name, while the `domain.tld` is set during initial configuration and stored in the `$DOKKU_ROOT/VHOST` file. It can then be modified with `dokku domains:add-global` and `dokku domains:remove-global`. This value is used as a default TLD for all applications on a host. If a FQDN such as `other.tld` is used as the application name, the default `$DOKKU_ROOT/VHOST` will be ignored and the resulting vhost URL for that application will be `other.tld`. The exception to this rule being that if the FQDN has the same ending as the default vhost (such as `subdomain.domain.tld`), then the entire FQDN will be treated as a subdomain. The application will therefore be deployed at `subdomain.domain.tld.domain.tld`. diff --git a/plugins/common/functions b/plugins/common/functions index 4948d4d2a..7018e1766 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -818,24 +818,28 @@ get_ipv6_regex() { echo "${RE_IPV6}\$" } -get_global_vhost() { - declare desc="return global vhost" +get_global_vhosts() { + declare desc="return global vhosts" local GLOBAL_VHOST_FILE="$DOKKU_ROOT/VHOST" - [[ -f "$GLOBAL_VHOST_FILE" ]] && local GLOBAL_VHOST=$(< "$GLOBAL_VHOST_FILE") - echo "$GLOBAL_VHOST" + [[ -f "$GLOBAL_VHOST_FILE" ]] && local GLOBAL_VHOSTS=$(< "$GLOBAL_VHOST_FILE") + echo "$GLOBAL_VHOSTS" } is_global_vhost_enabled() { declare desc="returns true if we have a valid global vhost set; otherwise returns false" - local GLOBAL_VHOST=$(get_global_vhost) - local GLOBAL_VHOST_ENABLED=true + local GLOBAL_VHOSTS=$(get_global_vhosts) + local GLOBAL_VHOSTS_ENABLED=false local RE_IPV4="$(get_ipv4_regex)" local RE_IPV6="$(get_ipv6_regex)" - if [[ -z "$GLOBAL_VHOST" ]] || [[ "$GLOBAL_VHOST" =~ $RE_IPV4 ]] || [[ "$GLOBAL_VHOST" =~ $RE_IPV6 ]]; then - local GLOBAL_VHOST_ENABLED=false - fi - echo $GLOBAL_VHOST_ENABLED + while read -r GLOBAL_VHOST; do + if (is_valid_hostname "$GLOBAL_VHOST"); then + local GLOBAL_VHOSTS_ENABLED=true + break + fi + done <<< "$GLOBAL_VHOSTS" + + echo $GLOBAL_VHOSTS_ENABLED } is_app_vhost_enabled() { diff --git a/plugins/domains/commands b/plugins/domains/commands index 42ce3a8c3..e7f12bf2f 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -9,11 +9,12 @@ case "$1" in cat<], List domains domains:add DOMAIN, Add a domain to app + domains:add-global DOMAIN, Add global domain name domains:clear , Clear all domains for app domains:disable , Disable VHOST support domains:enable , Enable VHOST support domains:remove DOMAIN, Remove a domain from app - domains:set-global , Set global domain name + domains:remove-global DOMAIN, Remove global domain name help_content } diff --git a/plugins/domains/functions b/plugins/domains/functions index 073444aae..2cc3a78a4 100755 --- a/plugins/domains/functions +++ b/plugins/domains/functions @@ -20,27 +20,30 @@ get_app_domains() { fi } -get_default_vhost() { - declare desc="return default vhost" +get_default_vhosts() { + declare desc="return default vhosts" verify_app_name "$1" local APP="$1"; local RE_IPV4="$(get_ipv4_regex)"; local RE_IPV6="$(get_ipv6_regex)" + if [[ "$(is_global_vhost_enabled)" == "true" ]]; then - local VHOST=$(get_global_vhost) - if ! ([[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]]); then - local SUBDOMAIN=${APP/%\.${VHOST}/} - local hostname=$(: | plugn trigger nginx-hostname "$APP" "$SUBDOMAIN" "$VHOST") - if [[ ! -n $hostname ]]; then - if [[ "$APP" == *.* ]] && [[ "$SUBDOMAIN" == "$APP" ]]; then - local hostname="${APP/\//-}" - else - local hostname="${APP/\//-}.$VHOST" + local VHOSTS=$(get_global_vhosts) + + while read -r VHOST; do + if ! ([[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]]); then + local SUBDOMAIN=${APP/%\.${VHOST}/} + local hostname=$(: | plugn trigger nginx-hostname "$APP" "$SUBDOMAIN" "$VHOST") + if [[ ! -n $hostname ]]; then + if [[ "$APP" == *.* ]] && [[ "$SUBDOMAIN" == "$APP" ]]; then + local hostname="${APP/\//-}" + else + local hostname="${APP/\//-}.$VHOST" + fi fi + echo "$hostname" fi - local DEFAULT_VHOST="$hostname" - fi + done <<< "$VHOSTS" fi - echo "$DEFAULT_VHOST" } domains_setup() { @@ -48,12 +51,12 @@ domains_setup() { verify_app_name "$1" local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST"; local GLOBAL_VHOST_PATH="$DOKKU_ROOT/VHOST" local RE_IPV4="$(get_ipv4_regex)"; local RE_IPV6="$(get_ipv6_regex)" - local DEFAULT_VHOST="$(get_default_vhost "$APP")" + local DEFAULT_VHOSTS="$(get_default_vhosts "$APP")" if [[ ! -f $APP_VHOST_PATH ]]; then - if [[ -n "$DEFAULT_VHOST" ]]; then + if [[ -n "$DEFAULT_VHOSTS" ]]; then dokku_log_info1 "Creating new $APP_VHOST_PATH..." - echo "$DEFAULT_VHOST" > "$APP_VHOST_PATH" + echo "$DEFAULT_VHOSTS" > "$APP_VHOST_PATH" else dokku_log_info2 "no global VHOST set. disabling vhost support" disable_app_vhost "$APP" --no-restart @@ -93,11 +96,10 @@ domains_remove() { declare desc="remove list of app domains" verify_app_name "$1" local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" - local DEFAULT_VHOST="$(get_default_vhost "$APP")" shift 1 for DOMAIN in "$@"; do - sed -i "\|^$DOMAIN\$|d" "$DOKKU_ROOT/$APP/VHOST" + sed -i "\|^$DOMAIN\$|d" "$APP_VHOST_PATH" dokku_log_info1 "Removed $DOMAIN from $APP" done plugn trigger post-domains-update "$APP" "remove" "$@" @@ -119,11 +121,11 @@ domains_enable() { declare desc="enable domains/VHOST support" verify_app_name "$1" local APP="$1"; local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" - local DEFAULT_VHOST="$(get_default_vhost "$APP")" + local DEFAULT_VHOSTS="$(get_default_vhosts "$APP")" if [[ "$(is_app_vhost_enabled "$APP")" == "false" ]];then - if [[ -n "$DEFAULT_VHOST" ]]; then - echo "$DEFAULT_VHOST" > "$APP_VHOST_PATH" + if [[ -n "$DEFAULT_VHOSTS" ]]; then + echo "$DEFAULT_VHOSTS" > "$APP_VHOST_PATH" fi [[ "$2" == "--no-restart" ]] && local ENABLE_APP_VHOST_ARGS=$2 enable_app_vhost "$APP" "$ENABLE_APP_VHOST_ARGS" @@ -132,14 +134,32 @@ domains_enable() { fi } -domains_set_global() { - declare desc="set global domain name" - local NEW_GLOBAL_VHOST="$1"; local GLOBAL_VHOST_PATH="$DOKKU_ROOT/VHOST" +domains_add_global() { + declare desc="add list of global domains" + local GLOBAL_VHOST_PATH="$DOKKU_ROOT/VHOST" - if [[ -n "$NEW_GLOBAL_VHOST" ]]; then - echo "$NEW_GLOBAL_VHOST" > "$GLOBAL_VHOST_PATH" - dokku_log_info1 "Set global domain to $NEW_GLOBAL_VHOST" - else - dokku_log_fail "New global domain name must not be blank" - fi + for DOMAIN in "$@"; do + if ! (is_valid_hostname "$DOMAIN"); then + dokku_log_fail "$DOMAIN is invalid. exiting..." + fi + done + + for DOMAIN in "$@"; do + if [[ $(egrep -w "^$DOMAIN$" "$GLOBAL_VHOST_PATH" > /dev/null 2>&1; echo $?) -eq 0 ]]; then + dokku_log_info1 "Skipping: $DOMAIN already added" + else + echo "$DOMAIN" >> "$GLOBAL_VHOST_PATH" + dokku_log_info1 "Added $DOMAIN" + fi + done +} + +domains_remove_global() { + declare desc="remove list of domains" + local GLOBAL_VHOST_PATH="$DOKKU_ROOT/VHOST" + + for DOMAIN in "$@"; do + sed -i "\|^$DOMAIN\$|d" "$GLOBAL_VHOST_PATH" + dokku_log_info1 "Removed $DOMAIN" + done } diff --git a/plugins/domains/subcommands/add-global b/plugins/domains/subcommands/add-global new file mode 100755 index 000000000..d71b27615 --- /dev/null +++ b/plugins/domains/subcommands/add-global @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_add_global_cmd() { + declare desc="add global domain name via command line" + local cmd="domains:add-global" + [[ -z $2 ]] && dokku_log_fail "Please specify a domain name. Usage: dokku $1 DOMAIN [DOMAIN ...]" + + shift 1 + domains_add_global "$@" +} + +domains_add_global_cmd "$@" diff --git a/plugins/domains/subcommands/default b/plugins/domains/subcommands/default index 7bf731c04..011a1c292 100755 --- a/plugins/domains/subcommands/default +++ b/plugins/domains/subcommands/default @@ -10,7 +10,7 @@ domains_main_cmd() { if [[ "$(is_global_vhost_enabled)" == "true" ]]; then dokku_log_info2_quiet "Global Domain Name" - get_global_vhost + get_global_vhosts fi if [[ -n "$APP" ]]; then verify_app_name "$APP" diff --git a/plugins/domains/subcommands/remove-global b/plugins/domains/subcommands/remove-global new file mode 100755 index 000000000..5a7c0ee80 --- /dev/null +++ b/plugins/domains/subcommands/remove-global @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +domains_remove_global_cmd() { + declare desc="remove global domain name via command line" + local cmd="domains:remove-global" + [[ -z $2 ]] && dokku_log_fail "Please specify a domain name. Usage: dokku $1 DOMAIN [DOMAIN ...]" + + shift 1 + domains_remove_global "$@" +} + +domains_remove_global_cmd "$@" diff --git a/plugins/domains/subcommands/set-global b/plugins/domains/subcommands/set-global deleted file mode 100755 index 18ae15a11..000000000 --- a/plugins/domains/subcommands/set-global +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/domains/functions" - -domains_set_global_cmd() { - declare desc="set global domain name from command line" - local cmd="domains:set-global" - [[ -z $2 ]] && dokku_log_fail "Please specify a global domain name" - domains_set_global "$2" -} - -domains_set_global_cmd "$@" diff --git a/tests/unit/20_domains.bats b/tests/unit/20_domains.bats index cd52c6190..173b36fc0 100644 --- a/tests/unit/20_domains.bats +++ b/tests/unit/20_domains.bats @@ -96,8 +96,8 @@ teardown() { assert_success } -@test "(domains) domains:set-global" { - run dokku domains:set-global global.dokku.me +@test "(domains) domains:add-global" { + run dokku domains:add-global global.dokku.me echo "output: "$output echo "status: "$status assert_success @@ -107,3 +107,55 @@ teardown() { echo "status: "$status assert_success } + +@test "(domains) domains:add-global (multiple)" { + run dokku domains:add-global global1.dokku.me global2.dokku.me global3.dokku.me + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku domains | grep -q global1.dokku.me" + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku domains | grep -q global2.dokku.me" + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku domains | grep -q global3.dokku.me" + echo "output: "$output + echo "status: "$status + assert_success +} + +@test "(domains) domains:remove-global" { + run dokku domains:add-global global.dokku.me + echo "output: "$output + echo "status: "$status + assert_success + + run dokku domains:remove-global global.dokku.me + echo "output: "$output + echo "status: "$status + refute_line "global.dokku.me" +} + +@test "(domains) domains (multiple global domains)" { + run dokku domains:add-global global1.dokku.me global2.dokku.me + echo "output: "$output + echo "status: "$status + assert_success + + dokku domains:setup $TEST_APP + run bash -c "dokku domains $TEST_APP | grep -q ${TEST_APP}.global1.dokku.me" + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku domains $TEST_APP | grep -q ${TEST_APP}.global2.dokku.me" + echo "output: "$output + echo "status: "$status + assert_success +}