From a9834560307bba7c3445c96e5071d29ea56277e4 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Mon, 24 Aug 2015 14:15:05 -0700 Subject: [PATCH 01/19] remove magic additions to VHOST based on SSL cert. fixes #1368 --- plugins/certs/commands | 22 ++++++++++++++ plugins/certs/functions | 45 +++++++++++++++++++++++++++ plugins/domains/commands | 3 +- plugins/domains/functions | 8 +++++ plugins/nginx-vhosts/commands | 57 ++++++++++++++++++++--------------- tests/unit/core.bats | 4 +-- tests/unit/nginx-vhosts.bats | 22 ++++---------- 7 files changed, 117 insertions(+), 44 deletions(-) create mode 100755 plugins/certs/commands create mode 100755 plugins/certs/functions create mode 100755 plugins/domains/functions diff --git a/plugins/certs/commands b/plugins/certs/commands new file mode 100755 index 000000000..a9918b038 --- /dev/null +++ b/plugins/certs/commands @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$(dirname $0)/../common/functions" +source "$(dirname $0)/functions" + +case "$1" in + help | certs:help) + cat && cat< CRT KEY, Add an ssl endpoint to an app. + certs:generate DOMAIN, Generate a key and certificate signing request (or self-signed certificate) + certs:info , Show certificate information for an ssl endpoint. + certs:key CRT KEY [KEY ...], Print the correct key for the given certificate. + certs:remove , Remove an SSL Endpoint from an app. + certs:update CRT KEY, Update an SSL Endpoint on an app. +EOF + ;; + + *) + exit $DOKKU_NOT_IMPLEMENTED_EXIT + ;; + +esac diff --git a/plugins/certs/functions b/plugins/certs/functions new file mode 100755 index 000000000..0f6dbd05c --- /dev/null +++ b/plugins/certs/functions @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_PATH/common/functions" + +# returns 'global', 'app', 'false' +# if both are configured, app trumps global +is_ssl_enabled() { + local APP=$1; verify_app_name $APP + APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + WILDCARD_SSL_PATH="$DOKKU_ROOT/tls" + + if [[ -e "$APP_SSL_PATH/server.crt" ]] && [[ -e "$APP_SSL_PATH/server.key" ]]; then + echo app + return 0 + elif [[ -e "$WILDCARD_SSL_PATH/server.crt" ]] && [[ -e "$WILDCARD_SSL_PATH/server.key" ]]; then + echo global + return 0 + else + echo false + return 1 + fi +} + +get_ssl_hostnames() { + local APP=$1; verify_app_name $APP + case "$(is_ssl_enabled $APP)" in + app) + SSL_PATH="$DOKKU_ROOT/$APP/tls" + ;; + + global) + SSL_PATH="$DOKKU_ROOT/tls" + ;; + esac + + SSL_HOSTNAME=$(openssl x509 -in $SSL_PATH/server.crt -noout -subject | tr '/' '\n' | grep CN= | cut -c4-) + SSL_HOSTNAME_ALT=$(openssl x509 -in $SSL_PATH/server.crt -noout -text | grep --after-context=1 '509v3 Subject Alternative Name:' | tail -n 1 | sed -e "s/[[:space:]]*DNS://g" | tr ',' '\n' || true) + if [[ -n "$SSL_HOSTNAME_ALT" ]]; then + SSL_HOSTNAMES="${SSL_HOSTNAME}\n${SSL_HOSTNAME_ALT}" + else + SSL_HOSTNAMES=$SSL_HOSTNAME + fi + echo -e $SSL_HOSTNAMES + return 0 +} diff --git a/plugins/domains/commands b/plugins/domains/commands index 73acd648e..399ff15d4 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -2,6 +2,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_PATH/common/functions" source "$PLUGIN_PATH/config/functions" +source "$PLUGIN_PATH/domains/functions" RE_IPV4="([0-9]{1,3}[\.]){3}[0-9]{1,3}" @@ -32,7 +33,7 @@ case "$1" in dokku domains:setup $APP if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then dokku_log_info2_quiet "$APP Domain Names" - cat "$DOKKU_ROOT/$APP/VHOST" + get_app_domains "$APP" else dokku_log_fail "No domain names set for $APP" fi diff --git a/plugins/domains/functions b/plugins/domains/functions new file mode 100755 index 000000000..f79e889ee --- /dev/null +++ b/plugins/domains/functions @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$(dirname $0)/../common/functions" + +get_app_domains() { + local APP=$1; verify_app_name $APP + cat "$DOKKU_ROOT/$APP/VHOST" +} diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index d2f400402..67838480b 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -1,7 +1,9 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_PATH/common/functions" +source "$PLUGIN_PATH/certs/functions" source "$PLUGIN_PATH/config/functions" +source "$PLUGIN_PATH/domains/functions" validate_nginx () { set +e @@ -32,8 +34,8 @@ case "$1" in verify_app_name "$APP" VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" URLS_PATH="$DOKKU_ROOT/$APP/URLS" - WILDCARD_SSL="$DOKKU_ROOT/tls" - SSL="$DOKKU_ROOT/$APP/tls" + WILDCARD_SSL_PATH="$DOKKU_ROOT/tls" + APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" APP_NGINX_TEMPLATE="$DOKKU_ROOT/$APP/nginx.conf.template" if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -z "$DOKKU_APP_LISTEN_IP" ]]; then @@ -58,17 +60,34 @@ case "$1" in [[ -f "$APP_NGINX_TEMPLATE" ]] && NGINX_TEMPLATE="$APP_NGINX_TEMPLATE" && NGINX_CUSTOM_TEMPLATE="true" && dokku_log_info1 'Overriding default nginx.conf with detected nginx.conf.template' 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" - SSL_DIRECTIVES=$(cat <> $VHOST_PATH - fi - - SSL_HOSTNAME_ALT=$(openssl x509 -in $SSL_INUSE/server.crt -noout -text | grep --after-context=1 '509v3 Subject Alternative Name:' | tail -n 1 | sed -e "s/[[:space:]]*DNS://g" | tr ',' '\n' || true) - if [[ -n "$SSL_HOSTNAME_ALT" ]]; then - SSL_HOSTNAME_ALT_REGEX=$(echo "$SSL_HOSTNAME_ALT" | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g') - [[ -z "$(egrep "^${SSL_HOSTNAME_ALT_REGEX}$" $VHOST_PATH)" ]] && [[ ! "$SSL_HOSTNAME_ALT" =~ ^\*.* ]] && echo "$SSL_HOSTNAME_ALT" >> $VHOST_PATH - fi - - SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$|^${SSL_HOSTNAME_ALT_REGEX}$" $VHOST_PATH || exit 0) - NONSSL_VHOSTS=$(egrep -v "^${SSL_HOSTNAME_REGEX}$|^${SSL_HOSTNAME_ALT_REGEX}$" $VHOST_PATH || exit 0) + SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH || true) + NONSSL_VHOSTS=$(egrep -v "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH || true) while read line; do [[ -z "$line" ]] && continue diff --git a/tests/unit/core.bats b/tests/unit/core.bats index 99c545a99..0d2641f27 100644 --- a/tests/unit/core.bats +++ b/tests/unit/core.bats @@ -99,9 +99,9 @@ build_nginx_config() { setup_test_tls assert_urls "https://dokku.me" build_nginx_config - assert_urls "https://node-js-app.dokku.me" "http://${TEST_APP}.dokku.me" + assert_urls "http://${TEST_APP}.dokku.me" add_domain "test.dokku.me" - assert_urls "https://node-js-app.dokku.me" "http://${TEST_APP}.dokku.me" "http://test.dokku.me" + assert_urls "http://${TEST_APP}.dokku.me" "http://test.dokku.me" } @test "(core) urls (wildcard ssl)" { diff --git a/tests/unit/nginx-vhosts.bats b/tests/unit/nginx-vhosts.bats index d08e7701c..fe2cf114a 100644 --- a/tests/unit/nginx-vhosts.bats +++ b/tests/unit/nginx-vhosts.bats @@ -74,9 +74,9 @@ assert_error_log() { } @test "(nginx-vhosts) logging" { - deploy_app - assert_access_log ${TEST_APP} - assert_error_log ${TEST_APP} + deploy_app + assert_access_log ${TEST_APP} + assert_error_log ${TEST_APP} } @test "(nginx-vhosts) nginx:build-config (wildcard SSL)" { @@ -109,21 +109,11 @@ assert_error_log() { assert_output "0" } -@test "(nginx-vhosts) nginx:build-config (with SSL CN mismatch)" { - setup_test_tls - deploy_app - assert_ssl_domain "node-js-app.dokku.me" -} - -@test "(nginx-vhosts) nginx:build-config (with SSL CN mismatch & custom nginx template)" { - setup_test_tls - custom_ssl_nginx_template - deploy_app - assert_ssl_domain "node-js-app.dokku.me" -} - @test "(nginx-vhosts) nginx:build-config (with SSL and Multiple SANs)" { setup_test_tls_with_sans + add_domain "test.dokku.me" + add_domain "www.test.dokku.me" + add_domain "www.test.app.dokku.me" deploy_app assert_ssl_domain "test.dokku.me" assert_ssl_domain "www.test.dokku.me" From f9da2d5c254ca2222873a3cfa00db29a98055b4c Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Mon, 24 Aug 2015 19:32:03 -0700 Subject: [PATCH 02/19] initial pass at cert plugin functionality --- plugins/certs/commands | 62 ++++++++++++++++++++++++++++++++++++++--- plugins/certs/functions | 1 - 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/plugins/certs/commands b/plugins/certs/commands index a9918b038..59be4550e 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -4,14 +4,68 @@ source "$(dirname $0)/../common/functions" source "$(dirname $0)/functions" case "$1" in + certs:generate) + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + APP="$2"; SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if [[ ! -f "$SSL_PATH/server.key" ]] && [[ ! -f "$SSL_PATH/server.crt" ]]; then + TMP_WORK_DIR=$(mktemp -d -t "dokku_certs.XXXXXXXXX") + trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' INT TERM EXIT + + pushd $TMP_WORK_DIR > /dev/null + + openssl genrsa -des3 -passout pass:x -out server.pass.key 2048 + openssl rsa -passin pass:x -in server.pass.key -out server.key + openssl req -new -key server.key -out server.csr + openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt + + mkdir -p "$DOKKU_ROOT/$APP/tls" + mv -f $TMP_WORK_DIR/server.key $TMP_WORK_DIR/server.crt $SSL_PATH + else + dokku_log_info1 "$APP has an SSL endpoint already defined" + fi + ;; + + certs:info) + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + APP="$2"; SSL_TYPE=$(is_ssl_enabled $APP); SSL_SELF_SIGNED=no + case "$SSL_TYPE" in + app) + SSL_PATH="$DOKKU_ROOT/$APP/tls" + ;; + + global) + SSL_PATH="$DOKKU_ROOT/tls" + ;; + + *) + ;; + esac + + if [[ -n "$SSL_PATH" ]]; then + dokku_log_info1 "Fetching SSL Endpoint info for $APP..." + dokku_log_info1 "Certificate details:" + dokku_log_info2 "Expires: $(openssl x509 -in $SSL_PATH/server.crt -noout -text | grep "Not After :" | awk -F " : " '{ print $2 }')" + dokku_log_info2 "Issuer: $(openssl x509 -in $SSL_PATH/server.crt -noout -text | grep "Issuer:" | xargs | sed -e "s/Issuer: //g")" + dokku_log_info2 "Starts At: $(openssl x509 -in $SSL_PATH/server.crt -noout -text | grep "Not Before:" | awk -F ": " '{ print $2 }')" + dokku_log_info2 "Subject: $(openssl x509 -in $SSL_PATH/server.crt -noout -subject | sed -e "s:subject= ::g"| sed -e "s:^/::g" | sed -e "s:/:; :g")" + (openssl verify "$SSL_PATH/server.crt" | grep -q "self signed certificate") && SSL_SELF_SIGNED=yes + dokku_log_info2 "Self signed: $SSL_SELF_SIGNED" + dokku_log_info2 "SSL Domains:" + for domain in $(get_ssl_hostnames $APP | xargs); do + dokku_log_info2 "$domain" + done + else + dokku_log_info1 "$APP does not have an SSL endpoint" + fi + ;; + help | certs:help) cat && cat< CRT KEY, Add an ssl endpoint to an app. certs:generate DOMAIN, Generate a key and certificate signing request (or self-signed certificate) certs:info , Show certificate information for an ssl endpoint. - certs:key CRT KEY [KEY ...], Print the correct key for the given certificate. - certs:remove , Remove an SSL Endpoint from an app. - certs:update CRT KEY, Update an SSL Endpoint on an app. EOF ;; diff --git a/plugins/certs/functions b/plugins/certs/functions index 0f6dbd05c..e125c72ed 100755 --- a/plugins/certs/functions +++ b/plugins/certs/functions @@ -16,7 +16,6 @@ is_ssl_enabled() { echo global return 0 else - echo false return 1 fi } From aec138ef32d8f21ca76b6bf22aed8668ef9736af Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Tue, 25 Aug 2015 13:32:35 -0700 Subject: [PATCH 03/19] heroku-like certs:info output --- plugins/certs/commands | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/plugins/certs/commands b/plugins/certs/commands index 59be4550e..f0d3d87f3 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -30,7 +30,7 @@ case "$1" in certs:info) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 verify_app_name "$2" - APP="$2"; SSL_TYPE=$(is_ssl_enabled $APP); SSL_SELF_SIGNED=no + APP="$2"; SSL_TYPE=$(is_ssl_enabled $APP) case "$SSL_TYPE" in app) SSL_PATH="$DOKKU_ROOT/$APP/tls" @@ -47,16 +47,23 @@ case "$1" in if [[ -n "$SSL_PATH" ]]; then dokku_log_info1 "Fetching SSL Endpoint info for $APP..." dokku_log_info1 "Certificate details:" - dokku_log_info2 "Expires: $(openssl x509 -in $SSL_PATH/server.crt -noout -text | grep "Not After :" | awk -F " : " '{ print $2 }')" + dokku_log_info2 "Common Name(s): " + + for domain in $(get_ssl_hostnames $APP | xargs); do + dokku_log_info2 " $domain" + done + + dokku_log_info2 "Expires At: $(openssl x509 -in $SSL_PATH/server.crt -noout -text | grep "Not After :" | awk -F " : " '{ print $2 }')" dokku_log_info2 "Issuer: $(openssl x509 -in $SSL_PATH/server.crt -noout -text | grep "Issuer:" | xargs | sed -e "s/Issuer: //g")" dokku_log_info2 "Starts At: $(openssl x509 -in $SSL_PATH/server.crt -noout -text | grep "Not Before:" | awk -F ": " '{ print $2 }')" dokku_log_info2 "Subject: $(openssl x509 -in $SSL_PATH/server.crt -noout -subject | sed -e "s:subject= ::g"| sed -e "s:^/::g" | sed -e "s:/:; :g")" - (openssl verify "$SSL_PATH/server.crt" | grep -q "self signed certificate") && SSL_SELF_SIGNED=yes - dokku_log_info2 "Self signed: $SSL_SELF_SIGNED" - dokku_log_info2 "SSL Domains:" - for domain in $(get_ssl_hostnames $APP | xargs); do - dokku_log_info2 "$domain" - done + SSL_VERIFY_OUTPUT="$(openssl verify -verbose -purpose sslserver $SSL_PATH/server.crt | awk -F ':' '{ print $2 }' | tail -1 | xargs || true)" + if [[ "$SSL_VERIFY_OUTPUT" == "OK" ]]; then + SSL_SELF_SIGNED="verified by a certificate authority." + else + SSL_SELF_SIGNED="self signed." + fi + dokku_log_info2 "SSL certificate is $SSL_SELF_SIGNED" else dokku_log_info1 "$APP does not have an SSL endpoint" fi From 983e0910b10f125d6c8a242cbeb005825a76f702 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Tue, 25 Aug 2015 16:41:13 -0700 Subject: [PATCH 04/19] implement certs:remove. spit out csr on certs:generate --- plugins/certs/commands | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/plugins/certs/commands b/plugins/certs/commands index f0d3d87f3..6aadee13d 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -7,7 +7,7 @@ case "$1" in certs:generate) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 verify_app_name "$2" - APP="$2"; SSL_PATH="$DOKKU_ROOT/$APP/tls" + APP="$2"; DOMAIN="$3"; SSL_PATH="$DOKKU_ROOT/$APP/tls" if [[ ! -f "$SSL_PATH/server.key" ]] && [[ ! -f "$SSL_PATH/server.crt" ]]; then TMP_WORK_DIR=$(mktemp -d -t "dokku_certs.XXXXXXXXX") @@ -22,6 +22,11 @@ case "$1" in mkdir -p "$DOKKU_ROOT/$APP/tls" mv -f $TMP_WORK_DIR/server.key $TMP_WORK_DIR/server.crt $SSL_PATH + [[ -n "$DOMAIN" ]] && dokku domains:add $APP $DOMAIN || true + dokku_log_info1 "The following is a certificate signing request that can be used" + dokku_log_info1 "to generate an 'officially' signed SSL certificate for $APP at $DOMAIN" + dokku_log_info1 "by a CA of your choosing." + cat server.csr else dokku_log_info1 "$APP has an SSL endpoint already defined" fi @@ -69,10 +74,25 @@ case "$1" in fi ;; + certs:remove) + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + APP="$2"; APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if [[ -d "$APP_SSL_PATH" ]]; then + dokku_log_info1 "Removing SSL endpoint from $APP" + rm -rf $APP_SSL_PATH + pluginhook post-domains-update $APP + else + dokku_log_info1 "An app-specific SSL endpoint is not defined" + fi + ;; + help | certs:help) cat && cat< DOMAIN, Generate a key and certificate signing request (or self-signed certificate) + certs:generate DOMAIN, Generate a key and certificate signing request (and self-signed certificate) certs:info , Show certificate information for an ssl endpoint. + certs:remove , Remove an SSL Endpoint from an app. EOF ;; From 5378337456cedf93a426dc328a5028c53fc93cb9 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Tue, 25 Aug 2015 16:41:26 -0700 Subject: [PATCH 05/19] document certs plugin --- docs/ssl-certificate-management.md | 34 ++++++++++++++++++++++++++++++ docs/template.html | 1 + 2 files changed, 35 insertions(+) create mode 100644 docs/ssl-certificate-management.md diff --git a/docs/ssl-certificate-management.md b/docs/ssl-certificate-management.md new file mode 100644 index 000000000..56c5de8a9 --- /dev/null +++ b/docs/ssl-certificate-management.md @@ -0,0 +1,34 @@ +# SSL Certificates + +Dokku supports SSL/TLS certificate inspection and CSR/Self-signed certificate generation via the `certs` plugin + +``` +certs:generate DOMAIN Generate a key and certificate signing request (and self-signed certificate) +certs:info Show certificate information for an ssl endpoint. +certs:remove Remove an SSL Endpoint from an app. +``` + +## Certificate generation + +The `certs:generate` command will walk you through the correct `openssl` commands to create a key, csr and a self-signed cert for a given app/domain. We automatically put the self-signed cert in place as well as add the specified domain to the application configuration. If you decide to obtain a CA signed certficate, simply place it in `$DOKKU_ROOT/$APP/tls/server.crt` and run `dokku nginx:build-config $APP`. + +### Certificate information + +The `certs:info` command will simply inspect the install SSL cert and print out details. NOTE: The server-wide certificate will be inspect if installed and no app-specific certificate exists. + +``` +root@dokku:~/dokku# dokku certs:info node-js-app +-----> Fetching SSL Endpoint info for node-js-app... +-----> Certificate details: +=====> Common Name(s): +=====> test.dokku.me +=====> Expires At: Aug 24 23:32:59 2016 GMT +=====> Issuer: C=US, ST=California, L=San Francisco, O=dokku.me, CN=test.dokku.me +=====> Starts At: Aug 25 23:32:59 2015 GMT +=====> Subject: C=US; ST=California; L=San Francisco; O=dokku.me; CN=test.dokku.me +=====> SSL certificate is self signed. +``` + +### `certs:remove` command + +The `certs:remove` command only works on app-specific certificates. It will `rm` the app-specific tls directory, rebuild the nginx configuration, and reload nginx. diff --git a/docs/template.html b/docs/template.html index f837ae117..30ff58c67 100644 --- a/docs/template.html +++ b/docs/template.html @@ -64,6 +64,7 @@ Process management DNS Configuration Nginx Configuration + SSL Configuration Running Remote commands Container Options Dokku Event Logs From 8ea5cfa2aaf644251dee88257ca3b41006de2dde Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Tue, 25 Aug 2015 16:45:04 -0700 Subject: [PATCH 06/19] document 'public' functions convention --- docs/development/plugin-creation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/development/plugin-creation.md b/docs/development/plugin-creation.md index 78f3e0f9e..90a7a338c 100644 --- a/docs/development/plugin-creation.md +++ b/docs/development/plugin-creation.md @@ -80,4 +80,5 @@ A few notes: dokku config:set --no-restart APP KEY1=VALUE1 [KEY2=VALUE2 ...] dokku config:unset --no-restart APP KEY1 [KEY2 ...] ``` +- From time to time you may want to allow other plugins access to (some of) your plugin's functionality. You can expose this by including a `functions` file in your plugin for others to source. Consider all functions in that file to be publicly accessible by other plugins. Any functions not wished to be made "public" should reside within your pluginhook or commands files. - As of 0.4.0, we allow image tagging and deployment of said tagged images. Therefore, hard-coding of `$IMAGE` as `dokku/$APP` is no longer sufficient. Instead, for non `pre/post-build-*` plugins, use `get_running_image_tag()` & `get_app_image_name()` as sourced from common/functions. See [pluginhooks](http://progrium.viewdocs.io/dokku/development/pluginhooks) doc for examples. From 5cb62b168f35606296646d3e90215ae10b031796 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Tue, 25 Aug 2015 17:02:46 -0700 Subject: [PATCH 07/19] lintball. also run nginx:build-config if domains:add fails --- plugins/certs/commands | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/certs/commands b/plugins/certs/commands index 6aadee13d..c046ffedb 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -21,8 +21,9 @@ case "$1" in openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt mkdir -p "$DOKKU_ROOT/$APP/tls" + dokku_log_info1 "Installing certificate and key..." mv -f $TMP_WORK_DIR/server.key $TMP_WORK_DIR/server.crt $SSL_PATH - [[ -n "$DOMAIN" ]] && dokku domains:add $APP $DOMAIN || true + [[ -n "$DOMAIN" ]] && (dokku domains:add $APP $DOMAIN || dokku nginx:build-config $APP) dokku_log_info1 "The following is a certificate signing request that can be used" dokku_log_info1 "to generate an 'officially' signed SSL certificate for $APP at $DOMAIN" dokku_log_info1 "by a CA of your choosing." From f2e153744cb71b7c1b41be0d00f5e04d8d96db05 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 3 Sep 2015 22:38:24 -0400 Subject: [PATCH 08/19] [ci skip] minor formatting changes --- plugins/ps/functions | 2 +- tests/test_deploy | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/ps/functions b/plugins/ps/functions index f0e5aef78..c21498f05 100755 --- a/plugins/ps/functions +++ b/plugins/ps/functions @@ -2,7 +2,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_PATH/common/functions" -print_dokku_scale_file(){ +print_dokku_scale_file() { local APP="$1"; local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" while read line || [ -n "$line" ] do diff --git a/tests/test_deploy b/tests/test_deploy index f1b46a0a6..07b0a27e4 100755 --- a/tests/test_deploy +++ b/tests/test_deploy @@ -5,17 +5,17 @@ SELF=$(which $0); APP="$1"; TARGET="$2"; FORWARDED_PORT="$3"; SHOULD_FAIL="$4" REMOTE="dokku@$TARGET" REPO="test-$(basename $APP)-$RANDOM" -destroy_app(){ +destroy_app() { echo $REPO | ssh $REMOTE apps:destroy $REPO } -failed(){ +failed() { echo "************ $1 failed ************" destroy_app exit 1 } -succeeded(){ +succeeded() { echo "************ $1 succeeded but should have failed ************" destroy_app exit 1 From d37e64d3d6f60c61630668a1e393dba43f3eef52 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 3 Sep 2015 23:00:35 -0400 Subject: [PATCH 09/19] Move nginx:import-ssl to certs:add --- docs/nginx.md | 6 ++--- plugins/certs/commands | 38 ++++++++++++++++++++++++++++++++ plugins/nginx-vhosts/commands | 41 ----------------------------------- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/docs/nginx.md b/docs/nginx.md index 3491a9bd6..832b256d8 100644 --- a/docs/nginx.md +++ b/docs/nginx.md @@ -15,7 +15,7 @@ To enable TLS connections to to one of your applications, do the following: * If you are not paranoid and need it just for a DEV or STAGING app, you can use http://www.selfsignedcertificate.com/ to generate your 2 files more easily. * Rename your files to server.key and server.crt * tar these 2 files together, *without* subdirectories. Example: tar cvf cert-key.tar server.crt server.key -* Install the pair for your app, like this: ssh dokku@ip-of-your-dokku-server nginx:import-ssl < cert-key.tar +* Install the pair for your app, like this: ssh dokku@ip-of-your-dokku-server certs:add < cert-key.tar You will need to repeat the steps above for each domain used to serve your app. You can't simply create a single tar with all key/cert files in it (see https://github.com/progrium/dokku/issues/1195). @@ -46,7 +46,7 @@ Beware that if you enable the header and a subsequent deploy of your application You can import ssl certificates via tarball using the following command: ``` bash -dokku nginx:import-ssl myapp < archive-of-certs.tar +dokku certs:add myapp < archive-of-certs.tar ``` This archive should is expanded via `tar xvf`. It should contain `server.crt` and `server.key`. @@ -152,7 +152,7 @@ On subsequent deploys, the nginx virtualhost will be discarded. This is useful w > New as of 0.3.10 -The domains plugin allows you to specify custom domains for applications. This plugin is aware of any ssl certificates that are imported via `nginx:import-ssl`. Be aware that setting `NO_VHOST` will override any custom domains. +The domains plugin allows you to specify custom domains for applications. This plugin is aware of any ssl certificates that are imported via `certs:add`. Be aware that setting `NO_VHOST` will override any custom domains. Custom domains are also backed up via the built-in `backup` plugin diff --git a/plugins/certs/commands b/plugins/certs/commands index c046ffedb..e667e8c81 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -4,6 +4,43 @@ source "$(dirname $0)/../common/functions" source "$(dirname $0)/functions" case "$1" in + certs:add) + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + [[ -t 0 ]] && echo "Tar archive containing server.crt and server.key expected on stdin" && exit 1 + APP="$2" + + TEMP_DIR=$(mktemp -d) + cd $TEMP_DIR + tar xvf - <&0 + + CRT_FILE_SEARCH=$(find . -type f -name "*.crt") + CRT_FILE_COUNT=$(printf "%s" "$CRT_FILE_SEARCH" | grep -c '^') + if [[ $CRT_FILE_COUNT -lt 1 ]]; then + echo "Tar archive is missing .crt file" && exit 1 + elif [[ $CRT_FILE_COUNT -gt 1 ]]; then + echo "Tar archive contains more than one .crt file" && exit 1 + else + CRT_FILE=$CRT_FILE_SEARCH + fi + + KEY_FILE_SEARCH=$(find . -type f -name "*.key") + KEY_FILE_COUNT=$(printf "%s" "$KEY_FILE_SEARCH" | grep -c '^') + if [[ $KEY_FILE_COUNT -lt 1 ]]; then + echo "Tar archive is missing .key file" && exit 1 + elif [[ $KEY_FILE_COUNT -gt 1 ]]; then + echo "Tar archive contains more than one .key file" && exit 1 + else + KEY_FILE=$KEY_FILE_SEARCH + fi + + mkdir -p "$DOKKU_ROOT/$APP/tls" + mv "$CRT_FILE" "$DOKKU_ROOT/$APP/tls/server.crt" + mv "$KEY_FILE" "$DOKKU_ROOT/$APP/tls/server.key" + cd $DOKKU_ROOT + rm -rf $TEMP_DIR + dokku nginx:build-config $APP + ;; certs:generate) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 verify_app_name "$2" @@ -91,6 +128,7 @@ case "$1" in help | certs:help) cat && cat<, Add an ssl endpoint to an app. Imports a tarball from stdin; should contain server.crt and server.key certs:generate DOMAIN, Generate a key and certificate signing request (and self-signed certificate) certs:info , Show certificate information for an ssl endpoint. certs:remove , Remove an SSL Endpoint from an app. diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index 67838480b..e3dd21c4d 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -159,49 +159,8 @@ EOF fi fi ;; - - nginx:import-ssl) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 - verify_app_name "$2" - [[ -t 0 ]] && echo "Tar archive containing server.crt and server.key expected on stdin" && exit 1 - APP="$2" - - TEMP_DIR=$(mktemp -d) - cd $TEMP_DIR - tar xvf - <&0 - - CRT_FILE_SEARCH=$(find . -type f -name "*.crt") - CRT_FILE_COUNT=$(printf "%s" "$CRT_FILE_SEARCH" | grep -c '^') - if [[ $CRT_FILE_COUNT -lt 1 ]]; then - echo "Tar archive is missing .crt file" && exit 1 - elif [[ $CRT_FILE_COUNT -gt 1 ]]; then - echo "Tar archive contains more than one .crt file" && exit 1 - else - CRT_FILE=$CRT_FILE_SEARCH - fi - - KEY_FILE_SEARCH=$(find . -type f -name "*.key") - KEY_FILE_COUNT=$(printf "%s" "$KEY_FILE_SEARCH" | grep -c '^') - if [[ $KEY_FILE_COUNT -lt 1 ]]; then - echo "Tar archive is missing .key file" && exit 1 - elif [[ $KEY_FILE_COUNT -gt 1 ]]; then - echo "Tar archive contains more than one .key file" && exit 1 - else - KEY_FILE=$KEY_FILE_SEARCH - fi - - - mkdir -p "$DOKKU_ROOT/$APP/tls" - mv "$CRT_FILE" "$DOKKU_ROOT/$APP/tls/server.crt" - mv "$KEY_FILE" "$DOKKU_ROOT/$APP/tls/server.key" - cd $DOKKU_ROOT - rm -rf $TEMP_DIR - dokku nginx:build-config $APP - ;; - help | nginx:help) cat && cat<, Imports a tarball from stdin; should contain server.crt and server.key nginx:build-config , (Re)builds nginx config for given app EOF ;; From db4e847e8db848315fc5f368b8b1ccc723fe7401 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 3 Sep 2015 23:31:18 -0400 Subject: [PATCH 10/19] Update documentation on ssl management Also move into subdirectory [ci skip] --- docs/deployment/ssl-configuration.md | 90 ++++++++++++++++++++++++++++ docs/nginx.md | 51 ++-------------- docs/ssl-certificate-management.md | 34 ----------- docs/template.html | 2 +- plugins/certs/commands | 1 + 5 files changed, 96 insertions(+), 82 deletions(-) create mode 100644 docs/deployment/ssl-configuration.md delete mode 100644 docs/ssl-certificate-management.md diff --git a/docs/deployment/ssl-configuration.md b/docs/deployment/ssl-configuration.md new file mode 100644 index 000000000..7bfce70d2 --- /dev/null +++ b/docs/deployment/ssl-configuration.md @@ -0,0 +1,90 @@ +# SSL Configuration + +> New as of 0.4.0 + +Dokku supports SSL/TLS certificate inspection and CSR/Self-signed certificate generation via the `certs` plugin. Note that whenever SSL/TLS support is enabled SPDY is also enabled. + +``` +certs:add Add an ssl endpoint to an app. Imports a tarball from stdin; should contain server.crt and server.key +certs:generate DOMAIN Generate a key and certificate signing request (and self-signed certificate) +certs:info Show certificate information for an ssl endpoint. +certs:remove Remove an SSL Endpoint from an app. +``` + +## Per-application certificate management + +Dokku provides built-in support for managing SSL certificates on a per-application basis. SSL is managed via nginx outside of application containers, and as such can be updated on-the-fly without rebuilding containers. + +### Certificate setting + +The `certs:add` command can be used to push a `tar` containing a certificate `.crt` and `.key` file to a single application. The command should correctly handle cases where the `.crt` and `.key` are not named properly or are nested in a subdirectory of said `tar` file. You can import it as follows: + +```shell +tar cvf cert-key.tar server.crt server.key +# replace APP with your app name +dokku certs:add < cert-key.tar +``` + +You will need to repeat the steps above for each domain used to serve your app. You can't simply create a single tar with all key/cert files in it (see this [issue](https://github.com/progrium/dokku/issues/1195) for more details). + +### Certificate generation + +> Note: Using this method will create a self-signed certificate, which is only recommended for development or staging use, not production environments. + +The `certs:generate` command will walk you through the correct `openssl` commands to create a key, csr and a self-signed cert for a given app/domain. We automatically put the self-signed cert in place as well as add the specified domain to the application configuration. If you decide to obtain a CA signed certficate, simply place it in `$DOKKU_ROOT/$APP/tls/server.crt` and run `dokku nginx:build-config $APP`. + +### Certificate information + +The `certs:info` command will simply inspect the install SSL cert and print out details. NOTE: The server-wide certificate will be inspect if installed and no app-specific certificate exists. + +``` +root@dokku:~/dokku# dokku certs:info node-js-app +-----> Fetching SSL Endpoint info for node-js-app... +-----> Certificate details: +=====> Common Name(s): +=====> test.dokku.me +=====> Expires At: Aug 24 23:32:59 2016 GMT +=====> Issuer: C=US, ST=California, L=San Francisco, O=dokku.me, CN=test.dokku.me +=====> Starts At: Aug 25 23:32:59 2015 GMT +=====> Subject: C=US; ST=California; L=San Francisco; O=dokku.me; CN=test.dokku.me +=====> SSL certificate is self signed. +``` + +### `certs:remove` command + +The `certs:remove` command only works on app-specific certificates. It will `rm` the app-specific tls directory, rebuild the nginx configuration, and reload nginx. + +## Global Certification + +Global certificate management is a manual process. To enable TLS connections for all your applications at once you will need a wildcard TLS certificate. + +To enable TLS across all apps, you can run the following commands: + +```shell +mkdir -p /home/dokku/tls +cp server.crt /home/dokku/tls/server.crt +cp server.key /home/dokku/tls/server.key +``` + +Next, you will want to enable the certificates by editing `/etc/nginx/conf.d/dokku.conf` and uncommenting these two lines (remove the `#`): + +``` +ssl_certificate /home/dokku/tls/server.crt; +ssl_certificate_key /home/dokku/tls/server.key; +``` + +The settings will take affect at the next deploy. If you would like to propagate the change to all apps immediately, you can also run the following command: + +```shell +dokku ps:restartall +``` + +Once TLS is enabled, the application will be accessible by `https://` (redirection from `http://` is applied as well). + +> Note: TLS will not be enabled unless the application's VHOST matches the certificate's name. (i.e. if you have a cert for `*.example.com` TLS won't be enabled for `something.example.org` or `example.net`) + +## HSTS Header + +The [HSTS header](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) is an HTTP header that can inform browsers that all requests to a given site should be made via HTTPS. dokku does not, by default, enable this header. It is thus left up to you, the user, to enable it for your site. + +Beware that if you enable the header and a subsequent deploy of your application results in an HTTP deploy (for whatever reason), the way the header works means that a browser will not attempt to request the HTTP version of your site if the HTTPS version fails. diff --git a/docs/nginx.md b/docs/nginx.md index 832b256d8..e09c1ce65 100644 --- a/docs/nginx.md +++ b/docs/nginx.md @@ -2,54 +2,11 @@ Dokku uses nginx as it's server for routing requests to specific applications. By default, access and error logs are written for each app to `/var/log/nginx/${APP}-access.log` and `/var/log/nginx/${APP}-error.log` respectively -## TLS/SPDY support +## SSL Configuration -Dokku provides easy TLS/SPDY support out of the box. This can be done app-by-app or for all subdomains at once. Note that whenever TLS support is enabled SPDY is also enabled. +> New as of 0.4.0. -### Per App - -To enable TLS connections to to one of your applications, do the following: - -* Create a key file and a cert file. - * You can find detailed steps for generating a self-signed certificate at https://devcenter.heroku.com/articles/ssl-certificate-self - * If you are not paranoid and need it just for a DEV or STAGING app, you can use http://www.selfsignedcertificate.com/ to generate your 2 files more easily. -* Rename your files to server.key and server.crt -* tar these 2 files together, *without* subdirectories. Example: tar cvf cert-key.tar server.crt server.key -* Install the pair for your app, like this: ssh dokku@ip-of-your-dokku-server certs:add < cert-key.tar - -You will need to repeat the steps above for each domain used to serve your app. You can't simply create a single tar with all key/cert files in it (see https://github.com/progrium/dokku/issues/1195). - - -### All Subdomains - -To enable TLS connections for all your applications at once you will need a wildcard TLS certificate. - -To enable TLS across all apps, copy or symlink the `.crt` and `.key` files into the `/home/dokku/tls` folder (create this folder if it doesn't exist) as `server.crt` and `server.key` respectively. Then, enable the certificates by editing `/etc/nginx/conf.d/dokku.conf` and uncommenting these two lines (remove the #): - -``` -ssl_certificate /home/dokku/tls/server.crt; -ssl_certificate_key /home/dokku/tls/server.key; -``` - -The nginx configuration will need to be reloaded in order for the updated TLS configuration to be applied. This can be done either via the init system or by re-deploying the application. Once TLS is enabled, the application will be accessible by `https://` (redirection from `http://` is applied as well). - -**Note**: TLS will not be enabled unless the application's VHOST matches the certificate's name. (i.e. if you have a cert for *.example.com TLS won't be enabled for something.example.org or example.net) - -### HSTS Header - -The [HSTS header](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) is an HTTP header that can inform browsers that all requests to a given site should be made via HTTPS. dokku does not, by default, enable this header. It is thus left up to you, the user, to enable it for your site. - -Beware that if you enable the header and a subsequent deploy of your application results in an HTTP deploy (for whatever reason), the way the header works means that a browser will not attempt to request the HTTP version of your site if the HTTPS version fails. - -### Importing ssl certificates - -You can import ssl certificates via tarball using the following command: - -``` bash -dokku certs:add myapp < archive-of-certs.tar -``` - -This archive should is expanded via `tar xvf`. It should contain `server.crt` and `server.key`. +[See the full documentation](http://progrium.viewdocs.io/dokku/deployment/ssl-configuration). ## Customizing the nginx configuration @@ -152,7 +109,7 @@ On subsequent deploys, the nginx virtualhost will be discarded. This is useful w > New as of 0.3.10 -The domains plugin allows you to specify custom domains for applications. This plugin is aware of any ssl certificates that are imported via `certs:add`. Be aware that setting `NO_VHOST` will override any custom domains. +The domains plugin allows you to specify custom domains for applications. This plugin is aware of any ssl certificates that are imported via the `certs` plugin. Be aware that setting `NO_VHOST` will override any custom domains. Custom domains are also backed up via the built-in `backup` plugin diff --git a/docs/ssl-certificate-management.md b/docs/ssl-certificate-management.md deleted file mode 100644 index 56c5de8a9..000000000 --- a/docs/ssl-certificate-management.md +++ /dev/null @@ -1,34 +0,0 @@ -# SSL Certificates - -Dokku supports SSL/TLS certificate inspection and CSR/Self-signed certificate generation via the `certs` plugin - -``` -certs:generate DOMAIN Generate a key and certificate signing request (and self-signed certificate) -certs:info Show certificate information for an ssl endpoint. -certs:remove Remove an SSL Endpoint from an app. -``` - -## Certificate generation - -The `certs:generate` command will walk you through the correct `openssl` commands to create a key, csr and a self-signed cert for a given app/domain. We automatically put the self-signed cert in place as well as add the specified domain to the application configuration. If you decide to obtain a CA signed certficate, simply place it in `$DOKKU_ROOT/$APP/tls/server.crt` and run `dokku nginx:build-config $APP`. - -### Certificate information - -The `certs:info` command will simply inspect the install SSL cert and print out details. NOTE: The server-wide certificate will be inspect if installed and no app-specific certificate exists. - -``` -root@dokku:~/dokku# dokku certs:info node-js-app ------> Fetching SSL Endpoint info for node-js-app... ------> Certificate details: -=====> Common Name(s): -=====> test.dokku.me -=====> Expires At: Aug 24 23:32:59 2016 GMT -=====> Issuer: C=US, ST=California, L=San Francisco, O=dokku.me, CN=test.dokku.me -=====> Starts At: Aug 25 23:32:59 2015 GMT -=====> Subject: C=US; ST=California; L=San Francisco; O=dokku.me; CN=test.dokku.me -=====> SSL certificate is self signed. -``` - -### `certs:remove` command - -The `certs:remove` command only works on app-specific certificates. It will `rm` the app-specific tls directory, rebuild the nginx configuration, and reload nginx. diff --git a/docs/template.html b/docs/template.html index 30ff58c67..fa646570e 100644 --- a/docs/template.html +++ b/docs/template.html @@ -64,7 +64,7 @@ Process management DNS Configuration Nginx Configuration - SSL Configuration + SSL Configuration Running Remote commands Container Options Dokku Event Logs diff --git a/plugins/certs/commands b/plugins/certs/commands index e667e8c81..c42468d7a 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -41,6 +41,7 @@ case "$1" in rm -rf $TEMP_DIR dokku nginx:build-config $APP ;; + certs:generate) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 verify_app_name "$2" From 148d563b821ea9887d01c198a52dc5afc31df277 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 3 Sep 2015 23:37:23 -0400 Subject: [PATCH 11/19] Update note on replacing certificate --- docs/deployment/ssl-configuration.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/deployment/ssl-configuration.md b/docs/deployment/ssl-configuration.md index 7bfce70d2..d005c9739 100644 --- a/docs/deployment/ssl-configuration.md +++ b/docs/deployment/ssl-configuration.md @@ -31,7 +31,9 @@ You will need to repeat the steps above for each domain used to serve your app. > Note: Using this method will create a self-signed certificate, which is only recommended for development or staging use, not production environments. -The `certs:generate` command will walk you through the correct `openssl` commands to create a key, csr and a self-signed cert for a given app/domain. We automatically put the self-signed cert in place as well as add the specified domain to the application configuration. If you decide to obtain a CA signed certficate, simply place it in `$DOKKU_ROOT/$APP/tls/server.crt` and run `dokku nginx:build-config $APP`. +The `certs:generate` command will walk you through the correct `openssl` commands to create a key, csr and a self-signed cert for a given app/domain. We automatically put the self-signed cert in place as well as add the specified domain to the application configuration. + +If you decide to obtain a CA signed certficate, you can import that certicate using the aformentioned `dokku certs:add` command. ### Certificate information From 1371056b207a379f969727da5c2f900101ac3d79 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 3 Sep 2015 23:55:06 -0400 Subject: [PATCH 12/19] Update documentation regarding multiple ssl certificate usage [ci skip] --- docs/deployment/ssl-configuration.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/deployment/ssl-configuration.md b/docs/deployment/ssl-configuration.md index d005c9739..e720bf60b 100644 --- a/docs/deployment/ssl-configuration.md +++ b/docs/deployment/ssl-configuration.md @@ -13,7 +13,7 @@ certs:remove Remove an SSL Endpoi ## Per-application certificate management -Dokku provides built-in support for managing SSL certificates on a per-application basis. SSL is managed via nginx outside of application containers, and as such can be updated on-the-fly without rebuilding containers. +Dokku provides built-in support for managing SSL certificates on a per-application basis. SSL is managed via nginx outside of application containers, and as such can be updated on-the-fly without rebuilding containers. At this time, applications only support a single SSL certificate at a time. To support multiple domains for a single application, wildcard certificate usage is encouraged. ### Certificate setting @@ -25,8 +25,6 @@ tar cvf cert-key.tar server.crt server.key dokku certs:add < cert-key.tar ``` -You will need to repeat the steps above for each domain used to serve your app. You can't simply create a single tar with all key/cert files in it (see this [issue](https://github.com/progrium/dokku/issues/1195) for more details). - ### Certificate generation > Note: Using this method will create a self-signed certificate, which is only recommended for development or staging use, not production environments. From 71ebf1e476a6164dc0c0c7a4964345d829c1f292 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 4 Sep 2015 00:00:07 -0400 Subject: [PATCH 13/19] Add certs:update alias for certs:add --- plugins/certs/commands | 85 +++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/plugins/certs/commands b/plugins/certs/commands index c42468d7a..320f39221 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -3,43 +3,47 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$(dirname $0)/../common/functions" source "$(dirname $0)/functions" +certs_set() { + [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + verify_app_name "$2" + [[ -t 0 ]] && echo "Tar archive containing server.crt and server.key expected on stdin" && exit 1 + APP="$2" + + TEMP_DIR=$(mktemp -d) + cd $TEMP_DIR + tar xvf - <&0 + + CRT_FILE_SEARCH=$(find . -type f -name "*.crt") + CRT_FILE_COUNT=$(printf "%s" "$CRT_FILE_SEARCH" | grep -c '^') + if [[ $CRT_FILE_COUNT -lt 1 ]]; then + echo "Tar archive is missing .crt file" && exit 1 + elif [[ $CRT_FILE_COUNT -gt 1 ]]; then + echo "Tar archive contains more than one .crt file" && exit 1 + else + CRT_FILE=$CRT_FILE_SEARCH + fi + + KEY_FILE_SEARCH=$(find . -type f -name "*.key") + KEY_FILE_COUNT=$(printf "%s" "$KEY_FILE_SEARCH" | grep -c '^') + if [[ $KEY_FILE_COUNT -lt 1 ]]; then + echo "Tar archive is missing .key file" && exit 1 + elif [[ $KEY_FILE_COUNT -gt 1 ]]; then + echo "Tar archive contains more than one .key file" && exit 1 + else + KEY_FILE=$KEY_FILE_SEARCH + fi + + mkdir -p "$DOKKU_ROOT/$APP/tls" + mv "$CRT_FILE" "$DOKKU_ROOT/$APP/tls/server.crt" + mv "$KEY_FILE" "$DOKKU_ROOT/$APP/tls/server.key" + cd $DOKKU_ROOT + rm -rf $TEMP_DIR + dokku nginx:build-config $APP +} + case "$1" in certs:add) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 - verify_app_name "$2" - [[ -t 0 ]] && echo "Tar archive containing server.crt and server.key expected on stdin" && exit 1 - APP="$2" - - TEMP_DIR=$(mktemp -d) - cd $TEMP_DIR - tar xvf - <&0 - - CRT_FILE_SEARCH=$(find . -type f -name "*.crt") - CRT_FILE_COUNT=$(printf "%s" "$CRT_FILE_SEARCH" | grep -c '^') - if [[ $CRT_FILE_COUNT -lt 1 ]]; then - echo "Tar archive is missing .crt file" && exit 1 - elif [[ $CRT_FILE_COUNT -gt 1 ]]; then - echo "Tar archive contains more than one .crt file" && exit 1 - else - CRT_FILE=$CRT_FILE_SEARCH - fi - - KEY_FILE_SEARCH=$(find . -type f -name "*.key") - KEY_FILE_COUNT=$(printf "%s" "$KEY_FILE_SEARCH" | grep -c '^') - if [[ $KEY_FILE_COUNT -lt 1 ]]; then - echo "Tar archive is missing .key file" && exit 1 - elif [[ $KEY_FILE_COUNT -gt 1 ]]; then - echo "Tar archive contains more than one .key file" && exit 1 - else - KEY_FILE=$KEY_FILE_SEARCH - fi - - mkdir -p "$DOKKU_ROOT/$APP/tls" - mv "$CRT_FILE" "$DOKKU_ROOT/$APP/tls/server.crt" - mv "$KEY_FILE" "$DOKKU_ROOT/$APP/tls/server.key" - cd $DOKKU_ROOT - rm -rf $TEMP_DIR - dokku nginx:build-config $APP + certs_set "$@" ;; certs:generate) @@ -69,7 +73,7 @@ case "$1" in else dokku_log_info1 "$APP has an SSL endpoint already defined" fi - ;; + ;; certs:info) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 @@ -111,7 +115,7 @@ case "$1" in else dokku_log_info1 "$APP does not have an SSL endpoint" fi - ;; + ;; certs:remove) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 @@ -125,7 +129,11 @@ case "$1" in else dokku_log_info1 "An app-specific SSL endpoint is not defined" fi - ;; + ;; + + certs:update) + certs_set "$@" + ;; help | certs:help) cat && cat< DOMAIN, Generate a key and certificate signing request (and self-signed certificate) certs:info , Show certificate information for an ssl endpoint. certs:remove , Remove an SSL Endpoint from an app. + certs:update , Update an SSL Endpoint on an app. Imports a tarball from stdin; should contain server.crt and server.key EOF ;; From 76cf4d2969fa7429cd66fe9517ed29067a04b044 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 4 Sep 2015 00:13:48 -0400 Subject: [PATCH 14/19] Add support for certificate setting via files on disk (when on server) This can be used as an alternative to importing via stdin, which may be preferred when working directly on a server, or via scripted installation/deployments. --- docs/deployment/ssl-configuration.md | 5 +- plugins/certs/commands | 71 ++++++++++++++++++---------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/docs/deployment/ssl-configuration.md b/docs/deployment/ssl-configuration.md index e720bf60b..327c296bc 100644 --- a/docs/deployment/ssl-configuration.md +++ b/docs/deployment/ssl-configuration.md @@ -5,10 +5,11 @@ Dokku supports SSL/TLS certificate inspection and CSR/Self-signed certificate generation via the `certs` plugin. Note that whenever SSL/TLS support is enabled SPDY is also enabled. ``` -certs:add Add an ssl endpoint to an app. Imports a tarball from stdin; should contain server.crt and server.key +certs:add CRT KEY Add an ssl endpoint to an app. Can also import from a tarball on stdin. certs:generate DOMAIN Generate a key and certificate signing request (and self-signed certificate) certs:info Show certificate information for an ssl endpoint. certs:remove Remove an SSL Endpoint from an app. +certs:update CRT KEY Update an SSL Endpoint on an app. Can also import from a tarball on stdin ``` ## Per-application certificate management @@ -50,7 +51,7 @@ root@dokku:~/dokku# dokku certs:info node-js-app =====> SSL certificate is self signed. ``` -### `certs:remove` command +### Certificate removal The `certs:remove` command only works on app-specific certificates. It will `rm` the app-specific tls directory, rebuild the nginx configuration, and reload nginx. diff --git a/plugins/certs/commands b/plugins/certs/commands index 320f39221..ad1da8b24 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -3,34 +3,53 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x source "$(dirname $0)/../common/functions" source "$(dirname $0)/functions" -certs_set() { - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 - verify_app_name "$2" - [[ -t 0 ]] && echo "Tar archive containing server.crt and server.key expected on stdin" && exit 1 - APP="$2" +is_tar_import() { + [[ -t 0 ]] && return 1 + return 0 +} - TEMP_DIR=$(mktemp -d) - cd $TEMP_DIR - tar xvf - <&0 +is_file_import() { + local CRT_FILE="$3" + local KEY_FILE="$4" - CRT_FILE_SEARCH=$(find . -type f -name "*.crt") - CRT_FILE_COUNT=$(printf "%s" "$CRT_FILE_SEARCH" | grep -c '^') - if [[ $CRT_FILE_COUNT -lt 1 ]]; then - echo "Tar archive is missing .crt file" && exit 1 - elif [[ $CRT_FILE_COUNT -gt 1 ]]; then - echo "Tar archive contains more than one .crt file" && exit 1 - else - CRT_FILE=$CRT_FILE_SEARCH + if [[ -f $CRT_FILE ]] && [[ -f $KEY_FILE]]; then + return 0 fi - KEY_FILE_SEARCH=$(find . -type f -name "*.key") - KEY_FILE_COUNT=$(printf "%s" "$KEY_FILE_SEARCH" | grep -c '^') - if [[ $KEY_FILE_COUNT -lt 1 ]]; then - echo "Tar archive is missing .key file" && exit 1 - elif [[ $KEY_FILE_COUNT -gt 1 ]]; then - echo "Tar archive contains more than one .key file" && exit 1 - else - KEY_FILE=$KEY_FILE_SEARCH + return 1 +} + +certs_set() { + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + verify_app_name "$2" + APP="$2"; CRT_FILE="$3"; KEY_FILE="$4" + + is_file_import || is_tar_import || dokku_log_fail "Tar archive containing server.crt and server.key expected on stdin" + + if is_tar_import + TEMP_DIR=$(mktemp -d) + cd $TEMP_DIR + tar xvf - <&0 + + CRT_FILE_SEARCH=$(find . -type f -name "*.crt") + CRT_FILE_COUNT=$(printf "%s" "$CRT_FILE_SEARCH" | grep -c '^') + if [[ $CRT_FILE_COUNT -lt 1 ]]; then + dokku_log_fail "Tar archive is missing .crt file" + elif [[ $CRT_FILE_COUNT -gt 1 ]]; then + dokku_log_fail "Tar archive contains more than one .crt file" + else + CRT_FILE=$CRT_FILE_SEARCH + fi + + KEY_FILE_SEARCH=$(find . -type f -name "*.key") + KEY_FILE_COUNT=$(printf "%s" "$KEY_FILE_SEARCH" | grep -c '^') + if [[ $KEY_FILE_COUNT -lt 1 ]]; then + dokku_log_fail "Tar archive is missing .key file" + elif [[ $KEY_FILE_COUNT -gt 1 ]]; then + dokku_log_fail "Tar archive contains more than one .key file" + else + KEY_FILE=$KEY_FILE_SEARCH + fi fi mkdir -p "$DOKKU_ROOT/$APP/tls" @@ -137,11 +156,11 @@ case "$1" in help | certs:help) cat && cat<, Add an ssl endpoint to an app. Imports a tarball from stdin; should contain server.crt and server.key + certs:add CRT KEY, Add an ssl endpoint to an app. Can also import from a tarball on stdin certs:generate DOMAIN, Generate a key and certificate signing request (and self-signed certificate) certs:info , Show certificate information for an ssl endpoint. certs:remove , Remove an SSL Endpoint from an app. - certs:update , Update an SSL Endpoint on an app. Imports a tarball from stdin; should contain server.crt and server.key + certs:update CRT KEY, Update an SSL Endpoint on an app. Can also import from a tarball on stdin EOF ;; From 95161a2a9f744482f32def282b590171df7c2585 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 4 Sep 2015 00:17:45 -0400 Subject: [PATCH 15/19] Use dokku_log_fail in all cases where there is an exit 1 --- docs/development/plugin-creation.md | 5 ++--- plugins/00_dokku-standard/commands | 16 ++++++---------- plugins/apps/commands | 6 +++--- plugins/backup/commands | 9 +++------ plugins/certs/commands | 9 ++++++--- plugins/config/functions | 4 ++-- plugins/domains/commands | 10 +++++----- plugins/ps/commands | 12 ++++++------ plugins/tags/commands | 8 ++++---- 9 files changed, 37 insertions(+), 42 deletions(-) diff --git a/docs/development/plugin-creation.md b/docs/development/plugin-creation.md index 90a7a338c..13ee06120 100644 --- a/docs/development/plugin-creation.md +++ b/docs/development/plugin-creation.md @@ -19,7 +19,7 @@ source "$PLUGIN_PATH/common/functions" case "$1" in hello) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_TAG=$(get_running_image_tag $APP); IMAGE=$(get_app_image_name $APP $IMAGE_TAG) verify_app_name "$APP" @@ -56,8 +56,7 @@ A few notes: ```shell IMAGE=$(docker images | grep "user/repo" | awk '{print $3}') if [[ -z $IMAGE ]]; then - echo "user/repo image not found... Did you run 'dokku plugins-install'?" - exit 1 + dokku_log_fail "user/repo image not found... Did you run 'dokku plugins-install'?" fi ``` diff --git a/plugins/00_dokku-standard/commands b/plugins/00_dokku-standard/commands index bd9864851..3d1838760 100755 --- a/plugins/00_dokku-standard/commands +++ b/plugins/00_dokku-standard/commands @@ -101,8 +101,7 @@ case "$1" in trace) [[ -d $DOKKU_ROOT/.dokkurc ]] || mkdir -p $DOKKU_ROOT/.dokkurc [[ "$2" == "on" ]] || [[ "$2" == "off" ]] || { - echo "Valid trace options are [on/off]" - exit 1 + dokku_log_fail "Valid trace options are [on/off]" } if [[ "$2" == "on" ]]; then @@ -121,7 +120,7 @@ case "$1" in ;; ls) - dokku_apps=$(ls -d $DOKKU_ROOT/*/ 2>/dev/null) || (echo "You haven't deployed any applications yet" && exit 1) + dokku_apps=$(ls -d $DOKKU_ROOT/*/ 2>/dev/null) || (dokku_log_fail "You haven't deployed any applications yet") dokku_col_log_info1_quiet "App Name" "Container Type" "Container Id" "Status" @@ -143,7 +142,7 @@ case "$1" in ;; logs) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; verify_app_name "$2" if (is_deployed $APP); then @@ -169,7 +168,7 @@ case "$1" in ;; run) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_TAG=$(get_running_image_tag $APP); IMAGE=$(get_app_image_name $APP $IMAGE_TAG) verify_app_name "$APP" @@ -185,7 +184,7 @@ case "$1" in ;; url | urls) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; verify_app_name "$2" eval "$(config_export app $APP)" @@ -217,10 +216,7 @@ case "$1" in ;; version) - cat "$DOKKU_ROOT/VERSION" || { - echo "Unable to determine dokku's version" 2>&1 - exit 1 - } + cat "$DOKKU_ROOT/VERSION" || dokku_log_fail "Unable to determine dokku's version" ;; help) diff --git a/plugins/apps/commands b/plugins/apps/commands index f2e29666d..55fdfb89a 100755 --- a/plugins/apps/commands +++ b/plugins/apps/commands @@ -9,7 +9,7 @@ case "$1" in ;; apps:create) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" [[ -d "$DOKKU_ROOT/$2" ]] && dokku_log_warn "Name is already taken" && exit 1 APP="$2" @@ -18,8 +18,8 @@ case "$1" in ;; apps:destroy) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 - [[ "$2" == "tls" ]] && echo "Unable to destroy tls directory" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" + [[ "$2" == "tls" ]] && dokku_log_fail "Unable to destroy tls directory" [[ "$3" == "force" ]] && DOKKU_APPS_FORCE_DELETE=1 APP="$2"; IMAGE_TAG=$(get_running_image_tag $APP) verify_app_name "$APP" diff --git a/plugins/backup/commands b/plugins/backup/commands index d964cde6e..1d1cf0655 100755 --- a/plugins/backup/commands +++ b/plugins/backup/commands @@ -50,14 +50,12 @@ case "$1" in tar xf $INPUT_FILE --directory=$BACKUP_TMP_DIR if [[ ! -f $BACKUP_TMP_DIR/.dokku_backup_version ]]; then - echo "Unable to determine backup version" - exit 1 + dokku_log_fail "Unable to determine backup version" fi VERSION=$(< $BACKUP_TMP_DIR/.dokku_backup_version) if [[ $VERSION -ne 1 ]]; then - echo "Unknown format version $VERSION" - exit 1 + dokku_log_fail "Unknown format version $VERSION" fi echo "Importing a version $VERSION backup..." @@ -69,8 +67,7 @@ case "$1" in if $force; then echo "-f used. Ignoring warnings." else - echo "Archive did not pass sanity checks. Use -f to import anyway" >&2 - exit 1 + dokku_log_fail "Archive did not pass sanity checks. Use -f to import anyway" fi fi diff --git a/plugins/certs/commands b/plugins/certs/commands index ad1da8b24..3bb1d14e6 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -66,7 +66,7 @@ case "$1" in ;; certs:generate) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2"; DOMAIN="$3"; SSL_PATH="$DOKKU_ROOT/$APP/tls" @@ -95,7 +95,7 @@ case "$1" in ;; certs:info) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2"; SSL_TYPE=$(is_ssl_enabled $APP) case "$SSL_TYPE" in @@ -137,7 +137,7 @@ case "$1" in ;; certs:remove) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2"; APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" @@ -157,9 +157,12 @@ case "$1" in help | certs:help) cat && cat< CRT KEY, Add an ssl endpoint to an app. Can also import from a tarball on stdin + certs:chain CRT [CRT ...], [NOT IMPLEMENTED] Print the ordered and complete chain for the given certificate. certs:generate DOMAIN, Generate a key and certificate signing request (and self-signed certificate) certs:info , Show certificate information for an ssl endpoint. + certs:key CRT KEY [KEY ...], [NOT IMPLEMENTED] Print the correct key for the given certificate. certs:remove , Remove an SSL Endpoint from an app. + certs:rollback , [NOT IMPLEMENTED] Rollback an SSL Endpoint for an app. certs:update CRT KEY, Update an SSL Endpoint on an app. Can also import from a tarball on stdin EOF ;; diff --git a/plugins/config/functions b/plugins/config/functions index bfdd610b2..a07d23fbc 100644 --- a/plugins/config/functions +++ b/plugins/config/functions @@ -38,7 +38,7 @@ config_parse_args() { if [[ "$DOKKU_CONFIG_TYPE" = "app" ]]; then if [[ -z $APP ]]; then - echo "Please specify an app to run the command on" >&2 && exit 1 + dokku_log_fail "Please specify an app to run the command on" else verify_app_name "$2" fi @@ -105,7 +105,7 @@ config_all() { is_config_export "$@" && config_export "$DOKKU_CONFIG_TYPE" "$APP" && exit 0 [[ "$APP" ]] && DOKKU_CONFIG_TYPE=$APP - [[ ! -s $ENV_FILE ]] && echo "no config vars for $DOKKU_CONFIG_TYPE" && exit 1 + [[ ! -s $ENV_FILE ]] && dokku_log_fail "no config vars for $DOKKU_CONFIG_TYPE" VARS=$(grep -Eo "export ([a-zA-Z_][a-zA-Z0-9_]*=.*)" $ENV_FILE | cut -d" " -f2-) diff --git a/plugins/domains/commands b/plugins/domains/commands index 399ff15d4..9f4f78a11 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -26,7 +26,7 @@ RE_IPV6="${RE_IPV6}\$" case "$1" in domains) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2" @@ -40,7 +40,7 @@ case "$1" in ;; domains:setup) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2"; VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" @@ -73,7 +73,7 @@ case "$1" in ;; domains:add) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2" @@ -103,7 +103,7 @@ case "$1" in ;; domains:clear) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2" @@ -115,7 +115,7 @@ case "$1" in ;; domains:remove) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$2" APP="$2" diff --git a/plugins/ps/commands b/plugins/ps/commands index 0acf81ac5..a24b10a58 100755 --- a/plugins/ps/commands +++ b/plugins/ps/commands @@ -5,7 +5,7 @@ source "$(dirname $0)/functions" case "$1" in ps) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; verify_app_name "$APP"; DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids $APP) ! (is_deployed $APP) && echo "App $APP has not been deployed" && exit 0 @@ -17,7 +17,7 @@ case "$1" in ;; ps:start) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_TAG=$(get_running_image_tag $APP); verify_app_name "$APP" @@ -31,7 +31,7 @@ case "$1" in ;; ps:stop) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids $APP) verify_app_name "$APP" @@ -46,7 +46,7 @@ case "$1" in ;; ps:rebuild) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; verify_app_name "$APP" pluginhook -p receive-app $APP @@ -63,7 +63,7 @@ case "$1" in ;; ps:restart) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_TAG=$(get_running_image_tag $APP) verify_app_name "$APP" @@ -83,7 +83,7 @@ case "$1" in ;; ps:scale) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_TAG=$(get_running_image_tag $APP) verify_app_name "$APP" diff --git a/plugins/tags/commands b/plugins/tags/commands index a77f8bc93..1d8fb3cef 100755 --- a/plugins/tags/commands +++ b/plugins/tags/commands @@ -5,7 +5,7 @@ source "$(dirname $0)/functions" case "$1" in tags) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_REPO=$(get_app_image_repo $APP) verify_app_name "$APP" @@ -14,7 +14,7 @@ case "$1" in ;; tags:create) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_TAG="$3"; IMAGE_REPO=$(get_app_image_repo $APP) verify_app_name "$APP" @@ -24,7 +24,7 @@ case "$1" in ;; tags:deploy) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_TAG="$3" verify_app_name "$APP" @@ -32,7 +32,7 @@ case "$1" in ;; tags:destroy) - [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 + [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" APP="$2"; IMAGE_TAG="$3"; IMAGE_REPO=$(get_app_image_repo $APP) verify_app_name "$2" From adfc3a8101cf362a59c4d3565539a44ec00d9d42 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 4 Sep 2015 00:18:41 -0400 Subject: [PATCH 16/19] Use dokku_log_fail in favor of dokku_log_warn If a command will exit because of invalid input, that isn't a warning, it's a failure. --- plugins/apps/commands | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/apps/commands b/plugins/apps/commands index 55fdfb89a..47a1b304f 100755 --- a/plugins/apps/commands +++ b/plugins/apps/commands @@ -10,7 +10,7 @@ case "$1" in apps:create) [[ -z $2 ]] && dokku_log_fail "Please specify an app to run the command on" - [[ -d "$DOKKU_ROOT/$2" ]] && dokku_log_warn "Name is already taken" && exit 1 + [[ -d "$DOKKU_ROOT/$2" ]] && dokku_log_fail "Name is already taken" APP="$2" mkdir -p "$DOKKU_ROOT/$APP" @@ -32,8 +32,7 @@ case "$1" in read -p "> " app_name if [[ "$app_name" != "$APP" ]]; then - dokku_log_warn "Confirmation did not match $APP. Aborted." - exit 1 + dokku_log_fail "Confirmation did not match $APP. Aborted." fi fi From 515afa8d62741e33c1da0f88b1921c4fd4215178 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 3 Sep 2015 21:44:19 -0700 Subject: [PATCH 17/19] lintballs --- plugins/certs/commands | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/certs/commands b/plugins/certs/commands index 3bb1d14e6..a46e9865b 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -12,7 +12,7 @@ is_file_import() { local CRT_FILE="$3" local KEY_FILE="$4" - if [[ -f $CRT_FILE ]] && [[ -f $KEY_FILE]]; then + if [[ -f $CRT_FILE ]] && [[ -f $KEY_FILE ]]; then return 0 fi @@ -24,9 +24,9 @@ certs_set() { verify_app_name "$2" APP="$2"; CRT_FILE="$3"; KEY_FILE="$4" - is_file_import || is_tar_import || dokku_log_fail "Tar archive containing server.crt and server.key expected on stdin" + is_file_import $CRT_FILE $KEY_FILE || is_tar_import || dokku_log_fail "Tar archive containing server.crt and server.key expected on stdin" - if is_tar_import + if is_tar_import; then TEMP_DIR=$(mktemp -d) cd $TEMP_DIR tar xvf - <&0 From 3c894fd1307ed707dd6e1fcde3b2d3edffb3876d Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 4 Sep 2015 12:52:15 -0400 Subject: [PATCH 18/19] Move version into place before running copyfiles Otherwise `make addman` will fail during test runs --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5d04d1502..6ac803847 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ else BUILD_STACK_TARGETS = build-in-docker endif -.PHONY: all apt-update install copyfiles man-db version plugins dependencies sshcommand pluginhook docker aufs stack count dokku-installer vagrant-acl-add vagrant-dokku +.PHONY: all apt-update install version copyfiles man-db plugins dependencies sshcommand pluginhook docker aufs stack count dokku-installer vagrant-acl-add vagrant-dokku include tests.mk include deb.mk @@ -28,7 +28,7 @@ include deb.mk all: # Type "make install" to install. -install: dependencies copyfiles plugin-dependencies plugins version +install: dependencies version copyfiles plugin-dependencies plugins release: deb-all package_cloud packer From d50db13065741976472c5df4760dc34e705c1e19 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Fri, 4 Sep 2015 13:26:12 -0400 Subject: [PATCH 19/19] Re-add old ssl docs while 0.4.0 is still not released [ci skip] --- docs/nginx.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/docs/nginx.md b/docs/nginx.md index e09c1ce65..392070b60 100644 --- a/docs/nginx.md +++ b/docs/nginx.md @@ -2,11 +2,58 @@ Dokku uses nginx as it's server for routing requests to specific applications. By default, access and error logs are written for each app to `/var/log/nginx/${APP}-access.log` and `/var/log/nginx/${APP}-error.log` respectively -## SSL Configuration +## TLS/SPDY support -> New as of 0.4.0. +Dokku provides easy TLS/SPDY support out of the box. This can be done app-by-app or for all subdomains at once. Note that whenever TLS support is enabled SPDY is also enabled. -[See the full documentation](http://progrium.viewdocs.io/dokku/deployment/ssl-configuration). +### SSL Configuration + +In 0.4.0, SSL Configuration has been replaced by the [`certs` plugin](http://progrium.viewdocs.io/dokku/deployment/ssl-configuration)). For users of dokku 0.3.x, please refer to the following sections. + +### Per App + +To enable TLS connections to to one of your applications, do the following: + +* Create a key file and a cert file. + * You can find detailed steps for generating a self-signed certificate at https://devcenter.heroku.com/articles/ssl-certificate-self + * If you are not paranoid and need it just for a DEV or STAGING app, you can use http://www.selfsignedcertificate.com/ to generate your 2 files more easily. +* Rename your files to server.key and server.crt +* tar these 2 files together, *without* subdirectories. Example: tar cvf cert-key.tar server.crt server.key +* Install the pair for your app, like this: ssh dokku@ip-of-your-dokku-server nginx:import-ssl < cert-key.tar + +You will need to repeat the steps above for each domain used to serve your app. You can't simply create a single tar with all key/cert files in it (see https://github.com/progrium/dokku/issues/1195). + + +### All Subdomains + +To enable TLS connections for all your applications at once you will need a wildcard TLS certificate. + +To enable TLS across all apps, copy or symlink the `.crt` and `.key` files into the `/home/dokku/tls` folder (create this folder if it doesn't exist) as `server.crt` and `server.key` respectively. Then, enable the certificates by editing `/etc/nginx/conf.d/dokku.conf` and uncommenting these two lines (remove the #): + +``` +ssl_certificate /home/dokku/tls/server.crt; +ssl_certificate_key /home/dokku/tls/server.key; +``` + +The nginx configuration will need to be reloaded in order for the updated TLS configuration to be applied. This can be done either via the init system or by re-deploying the application. Once TLS is enabled, the application will be accessible by `https://` (redirection from `http://` is applied as well). + +**Note**: TLS will not be enabled unless the application's VHOST matches the certificate's name. (i.e. if you have a cert for *.example.com TLS won't be enabled for something.example.org or example.net) + +### HSTS Header + +The [HSTS header](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) is an HTTP header that can inform browsers that all requests to a given site should be made via HTTPS. dokku does not, by default, enable this header. It is thus left up to you, the user, to enable it for your site. + +Beware that if you enable the header and a subsequent deploy of your application results in an HTTP deploy (for whatever reason), the way the header works means that a browser will not attempt to request the HTTP version of your site if the HTTPS version fails. + +### Importing ssl certificates + +You can import ssl certificates via tarball using the following command: + +``` bash +dokku nginx:import-ssl myapp < archive-of-certs.tar +``` + +This archive should is expanded via `tar xvf`. It should contain `server.crt` and `server.key`. ## Customizing the nginx configuration @@ -109,7 +156,7 @@ On subsequent deploys, the nginx virtualhost will be discarded. This is useful w > New as of 0.3.10 -The domains plugin allows you to specify custom domains for applications. This plugin is aware of any ssl certificates that are imported via the `certs` plugin. Be aware that setting `NO_VHOST` will override any custom domains. +The domains plugin allows you to specify custom domains for applications. This plugin is aware of any ssl certificates that are imported via `nginx:import-ssl`. Be aware that setting `NO_VHOST` will override any custom domains. Custom domains are also backed up via the built-in `backup` plugin