letsencrypt_service 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #!/bin/bash
  2. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  3. seconds_to_wait=3600
  4. ACME_CA_URI="${ACME_CA_URI:-https://acme-v01.api.letsencrypt.org/directory}"
  5. ACME_TOS_HASH="${ACME_TOS_HASH:-6373439b9f29d67a5cd4d18cbc7f264809342dbf21cb2ba2fc7588df987a6221}"
  6. DEFAULT_KEY_SIZE=4096
  7. source /app/functions.sh
  8. create_link() {
  9. local readonly target=${1?missing target argument}
  10. local readonly source=${2?missing source argument}
  11. [[ -f "$target" ]] && return 1
  12. ln -sf "$source" "$target"
  13. }
  14. create_links() {
  15. local readonly base_domain=${1?missing base_domain argument}
  16. local readonly domain=${2?missing base_domain argument}
  17. if [[ ! -f "/etc/nginx/certs/$base_domain"/fullchain.pem || \
  18. ! -f "/etc/nginx/certs/$base_domain"/key.pem ]]; then
  19. return 1
  20. fi
  21. local return_code=1
  22. create_link "/etc/nginx/certs/$domain".crt "./$base_domain"/fullchain.pem
  23. return_code=$(( $return_code & $? ))
  24. create_link "/etc/nginx/certs/$domain".key "./$base_domain"/key.pem
  25. return_code=$(( $return_code & $? ))
  26. if [[ -f "/etc/nginx/certs/dhparam.pem" ]]; then
  27. create_link "/etc/nginx/certs/$domain".dhparam.pem ./dhparam.pem
  28. return_code=$(( $return_code & $? ))
  29. fi
  30. if [[ -f "/etc/nginx/certs/$base_domain"/chain.pem ]]; then
  31. create_link "/etc/nginx/certs/$domain".chain.pem "./$base_domain"/chain.pem
  32. return_code=$(( $return_code & $? ))
  33. fi
  34. return $return_code
  35. }
  36. update_certs() {
  37. [[ ! -f "$DIR"/letsencrypt_service_data ]] && return
  38. # Load relevant container settings
  39. unset LETSENCRYPT_CONTAINERS
  40. source "$DIR"/letsencrypt_service_data
  41. reload_nginx='false'
  42. for cid in "${LETSENCRYPT_CONTAINERS[@]}"; do
  43. # Derive host and email variable names
  44. host_varname="LETSENCRYPT_${cid}_HOST"
  45. # Array variable indirection hack: http://stackoverflow.com/a/25880676/350221
  46. hosts_array=$host_varname[@]
  47. email_varname="LETSENCRYPT_${cid}_EMAIL"
  48. keysize_varname="LETSENCRYPT_${cid}_KEYSIZE"
  49. cert_keysize="${!keysize_varname}"
  50. if [[ "$cert_keysize" == "<no value>" ]]; then
  51. cert_keysize=$DEFAULT_KEY_SIZE
  52. fi
  53. test_certificate_varname="LETSENCRYPT_${cid}_TEST"
  54. create_test_certificate=false
  55. if [[ $(lc "${!test_certificate_varname:-}") == true ]]; then
  56. create_test_certificate=true
  57. fi
  58. params_d_str=""
  59. [[ $DEBUG == true ]] && params_d_str+=" -v"
  60. hosts_array_expanded=("${!hosts_array}")
  61. # First domain will be our base domain
  62. base_domain="${hosts_array_expanded[0]}"
  63. if [[ "$create_test_certificate" == true ]]; then
  64. # Use staging acme end point
  65. acme_ca_uri="https://acme-staging.api.letsencrypt.org/directory"
  66. if [[ ! -f /etc/nginx/certs/.${base_domain}.test ]]; then
  67. # Remove old certificates
  68. rm -rf /etc/nginx/certs/${base_domain}
  69. for domain in "${!hosts_array}"; do
  70. rm -f /etc/nginx/certs/$domain.{crt,key,dhparam.pem}
  71. done
  72. touch /etc/nginx/certs/.${base_domain}.test
  73. fi
  74. else
  75. acme_ca_uri="$ACME_CA_URI"
  76. if [[ -f /etc/nginx/certs/.${base_domain}.test ]]; then
  77. # Remove old test certificates
  78. rm -rf /etc/nginx/certs/${base_domain}
  79. for domain in "${!hosts_array}"; do
  80. rm -f /etc/nginx/certs/$domain.{crt,key,dhparam.pem}
  81. done
  82. rm -f /etc/nginx/certs/.${base_domain}.test
  83. fi
  84. fi
  85. # Create directory for the first domain
  86. mkdir -p /etc/nginx/certs/$base_domain
  87. cd /etc/nginx/certs/$base_domain
  88. for domain in "${!hosts_array}"; do
  89. # Add all the domains to certificate
  90. params_d_str+=" -d $domain"
  91. # Add location configuration for the domain
  92. add_location_configuration "$domain" || reload_nginx
  93. done
  94. echo "Creating/renewal $base_domain certificates... (${hosts_array_expanded[*]})"
  95. /usr/bin/simp_le \
  96. -f account_key.json -f key.pem -f chain.pem -f fullchain.pem -f cert.pem \
  97. --tos_sha256 $ACME_TOS_HASH \
  98. $params_d_str \
  99. --cert_key_size=$cert_keysize \
  100. --email "${!email_varname}" \
  101. --server=$acme_ca_uri \
  102. --default_root /usr/share/nginx/html/
  103. simp_le_return=$?
  104. for altnames in ${hosts_array_expanded[@]:1}; do
  105. # Remove old CN domain that now are altnames
  106. rm -rf /etc/nginx/certs/$altnames
  107. done
  108. if [[ -z $base_domain ]]; then
  109. echo "inavalid stuff from container: ${cid}"
  110. fi
  111. if [[ ! -z $base_domain ]]; then
  112. for domain in "${!hosts_array}"; do
  113. create_links $base_domain $domain && reload_nginx='true'
  114. [[ $simp_le_return -eq 0 ]] && reload_nginx='true'
  115. done
  116. fi
  117. done
  118. [[ "$reload_nginx" == 'true' ]] && reload_nginx
  119. }
  120. pid=
  121. # Service Loop: When this script exits, start it again.
  122. trap '[[ $pid ]] && kill $pid; exec $0' EXIT
  123. trap 'trap - EXIT' INT TERM
  124. update_certs
  125. # Wait some amount of time
  126. echo "Sleep for ${seconds_to_wait}s"
  127. sleep $seconds_to_wait & pid=$!
  128. wait
  129. pid=