Created
February 23, 2025 23:21
-
-
Save gnanet/56d42eb9f430048c71ec927cd794637f to your computer and use it in GitHub Desktop.
acme.sh deploy-hook-script to deploy certificate to Hetzner Cloud API using hcloud command
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/bash | |
# Here is a script to deploy cert to Hetzner Cloud API using hcloud command | |
# | |
# it requires the hcloud binary from | |
# https://github.com/hetznercloud/cli | |
# | |
# it requires following environment variables: | |
# | |
# HCLOUD_API_TOKEN - this contains the token to the hcloud API | |
# | |
# Usage: | |
# | |
# export HCLOUD_API_TOKEN="your-token-here"; acme.sh --deploy -d www.mydomain.com --deploy-hook hcloud_api | |
# | |
# returns 0 means success, otherwise error | |
######## Public functions ##################### | |
#domain keyfile certfile cafile fullchain | |
hcloud_api_deploy() { | |
_cdomain="$1" | |
_ckey="$2" | |
_ckey_file="$2" | |
_ccert="$3" | |
_cca="$4" | |
_cfullchain="$5" | |
_cfullchain_file="$5" | |
_debug _cdomain "$_cdomain" | |
_debug _ckey "$_ckey" | |
_debug _ccert "$_ccert" | |
_debug _cca "$_cca" | |
_debug _cfullchain "$_cfullchain" | |
# validate required env vars | |
_getdeployconf HCLOUD_API_TOKEN | |
if [ -z "$HCLOUD_API_TOKEN" ]; then | |
_err "HCLOUD_API_TOKEN needs to be defined (contains token for Hetzner Cloud API)" | |
return 1 | |
fi | |
_savedeployconf HCLOUD_API_TOKEN "$HCLOUD_API_TOKEN" | |
HCLOUD_CMD=$(command -v hcloud) | |
if [ -z "$HCLOUD_CMD" ]; then | |
_err "Install hcloud command, or set HCLOUD_CMD, if you installed hcloud to an unusual path" | |
return 1 | |
fi | |
# JSON does not allow multiline strings. | |
# So replacing new-lines with "\n" here | |
_ckey=$(sed -z 's/\n/\\n/g' <"$2") | |
_ccert=$(sed -z 's/\n/\\n/g' <"$3") | |
_cca=$(sed -z 's/\n/\\n/g' <"$4") | |
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5") | |
Le_CertCreateTimeStr=$(_readdomainconf Le_CertCreateTimeStr) | |
_debug Le_CertCreateTimeStr "$Le_CertCreateTimeStr" | |
if [ -n "$Le_CertCreateTimeStr" ]; then | |
_cert_date=$(echo "${Le_CertCreateTimeStr}" | cut -d 'T' -f1 | tr -d '-') | |
else | |
_cert_date=$(date +%Y%m%d) | |
fi | |
_cert_name="$_cdomain $_cert_date" | |
_same_cert_id=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate list | grep $_cdomain | grep "$_cert_name"| grep -oE "^[0-9]+") | |
_info "export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate list | grep $_cdomain | grep \"$_cert_name\"| grep -oE \"^[0-9]+\"" | |
if [ -n "$_same_cert_id" ]; then | |
_err "Cert already exists: $_cert_name! $_cdomain ssl not renewed?" | |
exit 1 | |
fi | |
_old_cert_id=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate list | grep $_cdomain | grep -v "$_cert_name"| grep -oE "^[0-9]+") | |
if [ -n "$_old_cert_id" ]; then | |
_lb_list=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate describe $_old_cert_id --output json | grep -oE "used_by.:\[[^]]*\]" | grep -oE "id.:[0-9]+" | cut -d ':' -f2) | |
fi | |
_debug _cdomain "$_cdomain" | |
_debug _cert_name "$_cert_name" | |
_debug _json_ckey "$_ckey" | |
_debug _json_cfullchain "$_cfullchain" | |
_debug _old_cert_id "$_old_cert_id" | |
if [ -z "$_old_cert_id" ]; then | |
_info "$(__green "$_cdomain is new, creating it")" | |
_cnt_lb_resp=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} load-balancer list | grep -v "NETWORK ZONE" | wc -l) | |
if [[ $_cnt_lb_resp -eq 1 ]]; then | |
_info "$(__green "Found one single LB, collected lb_id")" | |
_lb_list=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} load-balancer list | grep -v "NETWORK ZONE" | cut -d ' ' -f1 ) | |
fi | |
if [ -f ${_cfullchain_file} ] && [ -f ${_ckey_file} ]; then | |
_create_resp=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate create --cert-file ${_cfullchain_file} --key-file ${_ckey_file} --domain ${_cdomain} --type upload --name "${_cert_name}" 2>&1 ) | |
_new_cert_id=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate list | grep "$_cert_name" | grep -oE "^[0-9]+") | |
_debug _create_resp "$_create_resp" | |
_info "$(__green "Appending ${_new_cert_id} to the cert_list of the LB")" | |
for _lb_id in $_lb_list; do | |
_old_certlist=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} load-balancer describe $_lb_id --output json | grep -oE ".certificates.:\[[0-9,]+\]" | grep -oE "[0-9,]+") | |
_new_certlist="${_old_certlist},${_new_cert_id}" | |
_response_lb=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} load-balancer update-service $_lb_id --listen-port 443 --http-certificates $_new_certlist 2>&1) | |
_debug _response_lb "$_response_lb" | |
done | |
else | |
_err "Missing PEM files for _cdomain" | |
exit 1 | |
fi | |
else | |
_info "$(__green "$_cdomain exists, updating it")" | |
#URL="https://api.hetzner.cloud/v1/certificates" | |
#export _H1="Authorization: Bearer $HCLOUD_API_TOKEN" | |
#export _H2="Content-Type: application/json" | |
#_result=$( _post "{\"name\":\"$_cert_name\",\"type\":\"uploaded\",\"certificate\":\"$_cfullchain\",\"private_key\":\"$_ckey\"}" "$URL" ) | |
#_new_cert_id=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate list | grep "$_cert_name" | grep -oE "^[0-9]+") | |
_cnt_lb_resp=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} load-balancer list | grep -v "NETWORK ZONE" | wc -l) | |
if [[ $_cnt_lb_resp -eq 1 ]]; then | |
_info "$(__green "Found one single LB, collected lb_id")" | |
_lb_list=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} load-balancer list | grep -v "NETWORK ZONE" | cut -d ' ' -f1 ) | |
fi | |
if [ -f ${_cfullchain_file} ] && [ -f ${_ckey_file} ]; then | |
_create_resp=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate create --cert-file ${_cfullchain_file} --key-file ${_ckey_file} --domain ${_cdomain} --type upload --name "${_cert_name}" 2>&1 ) | |
_new_cert_id=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate list | grep "$_cert_name" | grep -oE "^[0-9]+") | |
_debug _create_resp "$_create_resp" | |
else | |
_err "Missing PEM files for _cdomain" | |
exit 1 | |
fi | |
if [ -z "$_new_cert_id" ]; then | |
_err "Upload of $_cdomain failed, got no new_cert_id" | |
exit 1 | |
else | |
_info "$(__green "New cert id ${_new_cert_id}")" | |
fi | |
_debug _old_cert_id "$_old_cert_id" | |
for _lb_id in $_lb_list; do | |
_info "$(__green "Replacing old cert ${_old_cert_id} with new cert ${_new_cert_id} in the cert_list of the LB ${_lb_id}")" | |
_old_certlist=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} load-balancer describe $_lb_id --output json | grep -oE ".certificates.:\[[0-9,]+\]" | grep -oE "[0-9,]+") | |
_new_certlist=$(echo "$_old_certlist" | sed -e "s/$_old_cert_id/$_new_cert_id/g") | |
_debug _old_certlist ${_old_certlist} | |
_debug _new_certlist ${_new_certlist} | |
_response_lb=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} load-balancer update-service $_lb_id --listen-port 443 --http-certificates $_new_certlist 2>&1) | |
_debug _response_lb "$_response_lb" | |
done | |
_oldlb_list=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate describe $_old_cert_id --output json | grep -oE "used_by.:\[[^]]*\]" | grep -oE "id.:[0-9]+" | cut -d ':' -f2) | |
if [[ "x${_oldlb_list}" == "x" ]]; then | |
_del_resp=$(export HCLOUD_TOKEN=$HCLOUD_API_TOKEN; ${HCLOUD_CMD} certificate delete $_old_cert_id 2>&1) | |
_debug _del_resp "$_del_resp" | |
fi | |
fi | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment