Commit 1dab2ac7 authored by Pål Håland's avatar Pål Håland
Browse files

Updated with latest changes from Neilpang/dev

parents 8d38cf4d ec540743
......@@ -13,12 +13,6 @@ env:
global:
- SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64
addons:
apt:
sources:
- debian-sid # Grab shellcheck from the Debian repo (o_O)
packages:
- shellcheck
install:
- if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
......@@ -29,9 +23,7 @@ install:
script:
- echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)"
- command -V openssl && openssl version
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then chmod +x ~/shfmt ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt && chmod +x ~/shfmt && ~/shfmt -l -w -i 2 . ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
......@@ -40,7 +32,6 @@ script:
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
matrix:
fast_finish: true
......
FROM alpine:3.6
FROM alpine:3.9
RUN apk update -f \
&& apk --no-cache add -f \
openssl \
coreutils \
bind-tools \
curl \
socat \
tzdata \
&& rm -rf /var/cache/apk/*
ENV LE_CONFIG_HOME /acme.sh
......
......@@ -33,9 +33,9 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt)
- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty)
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
- [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html)
- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html)
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/)
- [archlinux](https://www.archlinux.org/packages/community/any/acme.sh)
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
- [CentOS Web Panel](http://centos-webpanel.com/)
- [lnmp.org](https://lnmp.org/)
......@@ -70,11 +70,16 @@ For all build statuses, check our [weekly build project](https://github.com/Neil
https://github.com/Neilpang/acmetest
# Supported CA
- Letsencrypt.org CA(default)
- [BuyPass.com CA](https://github.com/Neilpang/acme.sh/wiki/BuyPass.com-CA)
# Supported modes
- Webroot mode
- Standalone mode
- Standalone tls-alpn mode
- Apache mode
- Nginx mode
- DNS mode
......@@ -221,8 +226,20 @@ acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 5. Use Standalone ssl server to issue cert
**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))**
# 5. Use Apache mode
Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again.
```bash
acme.sh --issue --alpn -d example.com -d www.example.com -d cp.example.com
```
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 6. Use Apache mode
**(requires you to be root/sudoer, since it is required to interact with Apache server)**
......@@ -236,13 +253,13 @@ Just set string "apache" as the second argument and it will force use of apache
acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
```
**This apache mode is only to issue the cert, it will not change your apache config files.
**This apache mode is only to issue the cert, it will not change your apache config files.
You will need to configure your website config files to use the cert by yourself.
We don't want to mess your apache server, don't worry.**
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 6. Use Nginx mode
# 7. Use Nginx mode
**(requires you to be root/sudoer, since it is required to interact with Nginx server)**
......@@ -260,13 +277,13 @@ So, the config is not changed.
acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
```
**This nginx mode is only to issue the cert, it will not change your nginx config files.
**This nginx mode is only to issue the cert, it will not change your nginx config files.
You will need to configure your website config files to use the cert by yourself.
We don't want to mess your nginx server, don't worry.**
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 7. Automatic DNS API integration
# 8. Automatic DNS API integration
If your DNS provider supports API access, we can use that API to automatically issue the certs.
......@@ -315,9 +332,33 @@ You don't have to do anything manually!
1. zonomi.com DNS API
1. DreamHost.com API
1. DirectAdmin API
And:
1. KingHost (https://www.kinghost.com.br/)
1. Zilore (https://zilore.com)
1. Loopia.se API
1. acme-dns (https://github.com/joohoi/acme-dns)
1. TELE3 (https://www.tele3.cz)
1. EUSERV.EU (https://www.euserv.eu)
1. DNSPod.com API (https://www.dnspod.com)
1. Google Cloud DNS API
1. ConoHa (https://www.conoha.jp)
1. netcup DNS API (https://www.netcup.de)
1. GratisDNS.dk (https://gratisdns.dk)
1. Namecheap API (https://www.namecheap.com/)
1. MyDNS.JP API (https://www.mydns.jp/)
1. hosting.de (https://www.hosting.de)
1. Neodigit.net API (https://www.neodigit.net)
1. Exoscale.com API (https://www.exoscale.com/)
1. PointDNS API (https://pointhq.com/)
1. Active24.cz API (https://www.active24.cz/)
1. do.de API (https://www.do.de/)
1. Nexcess API (https://www.nexcess.net)
1. Thermo.io API (https://www.thermo.io)
1. Futurehosting API (https://www.futurehosting.com)
1. Rackspace Cloud DNS (https://www.rackspace.com)
1. Online.net API (https://online.net/)
1. MyDevil.net (https://www.mydevil.net/)
And:
**lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
(DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)**
......@@ -329,7 +370,9 @@ If your DNS provider is not on the supported list above, you can write your own
For more details: [How to use DNS API](dnsapi)
# 8. Use DNS manual mode:
# 9. Use DNS manual mode:
See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first.
If your dns provider doesn't support any api access, you can add the txt record by your hand.
......@@ -363,7 +406,7 @@ Ok, it's done.
**Please use dns api mode instead.**
# 9. Issue ECC certificates
# 10. Issue ECC certificates
`Let's Encrypt` can now issue **ECDSA** certificates.
......@@ -395,7 +438,7 @@ Valid values are:
# 10. Issue Wildcard certificates
# 11. Issue Wildcard certificates
It's simple, just give a wildcard domain as the `-d` parameter.
......@@ -405,7 +448,7 @@ acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf
# 11. How to renew the certs
# 12. How to renew the certs
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
......@@ -422,7 +465,7 @@ acme.sh --renew -d example.com --force --ecc
```
# 12. How to stop cert renewal
# 13. How to stop cert renewal
To stop renewal of a cert, you can execute the following to remove the cert from the renewal list:
......@@ -435,7 +478,7 @@ The cert/key file is not removed from the disk.
You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself.
# 13. How to upgrade `acme.sh`
# 14. How to upgrade `acme.sh`
acme.sh is in constant development, so it's strongly recommended to use the latest code.
......@@ -460,25 +503,25 @@ acme.sh --upgrade --auto-upgrade 0
```
# 14. Issue a cert from an existing CSR
# 15. Issue a cert from an existing CSR
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
# 15. Under the Hood
# 16. Under the Hood
Speak ACME language using shell, directly to "Let's Encrypt".
TODO:
# 16. Acknowledgments
# 17. Acknowledgments
1. Acme-tiny: https://github.com/diafygi/acme-tiny
2. ACME protocol: https://github.com/ietf-wg-acme/acme
# 17. License & Others
# 18. License & Others
License is GPLv3
......@@ -487,9 +530,9 @@ Please Star and Fork me.
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
# 18. Donate
# 19. Donate
Your donation makes **acme.sh** better:
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
[Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list)
#!/usr/bin/env sh
VER=2.7.8
VER=2.8.1
PROJECT_NAME="acme.sh"
......@@ -35,19 +35,18 @@ _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org"
VTYPE_HTTP="http-01"
VTYPE_DNS="dns-01"
VTYPE_TLS="tls-sni-01"
VTYPE_TLS2="tls-sni-02"
VTYPE_ALPN="tls-alpn-01"
LOCAL_ANY_ADDRESS="0.0.0.0"
MAX_RENEW=60
DEFAULT_RENEW=60
DEFAULT_DNS_SLEEP=120
NO_VALUE="no"
W_TLS="tls"
W_DNS="dns"
W_ALPN="alpn"
DNS_ALIAS_PREFIX="="
MODE_STATELESS="stateless"
......@@ -124,26 +123,23 @@ if [ -t 1 ]; then
fi
__green() {
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
printf '\033[1;31;32m'
if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
printf '\033[1;31;32m%b\033[0m' "$1"
return
fi
printf -- "%b" "$1"
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
printf '\033[0m'
fi
}
__red() {
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
printf '\033[1;31;40m'
if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
printf '\033[1;31;40m%b\033[0m' "$1"
return
fi
printf -- "%b" "$1"
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
printf '\033[0m'
fi
}
_printargs() {
_exitstatus="$?"
if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
printf -- "%s" "[$(date)] "
fi
......@@ -153,6 +149,8 @@ _printargs() {
printf -- "%s" "$1='$2'"
fi
printf "\n"
# return the saved exit status
return "$_exitstatus"
}
_dlg_versions() {
......@@ -188,6 +186,7 @@ _dlg_versions() {
#class
_syslog() {
_exitstatus="$?"
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then
return
fi
......@@ -201,6 +200,7 @@ _syslog() {
fi
fi
$__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1
return "$_exitstatus"
}
_log() {
......@@ -1050,7 +1050,7 @@ _idn() {
fi
}
#_createcsr cn san_list keyfile csrfile conf
#_createcsr cn san_list keyfile csrfile conf acmeValidationv1
_createcsr() {
_debug _createcsr
domain="$1"
......@@ -1058,6 +1058,7 @@ _createcsr() {
csrkey="$3"
csr="$4"
csrconf="$5"
acmeValidationv1="$6"
_debug2 domain "$domain"
_debug2 domainlist "$domainlist"
_debug2 csrkey "$csrkey"
......@@ -1066,7 +1067,9 @@ _createcsr() {
printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf"
if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
if [ "$acmeValidationv1" ]; then
printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf"
elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
#single domain
_info "Single domain" "$domain"
printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
......@@ -1088,6 +1091,10 @@ _createcsr() {
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
fi
if [ "$acmeValidationv1" ]; then
printf "\n1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}"
fi
_csr_cn="$(_idn "$domain")"
_debug2 _csr_cn "$_csr_cn"
if _contains "$(uname -a)" "MINGW"; then
......@@ -1138,12 +1145,17 @@ _readSubjectAltNamesFromCSR() {
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
_debug "AltNames contains subject"
_dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")"
_excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')"
_debug _excapedAlgnames "$_excapedAlgnames"
_escapedSubject="$(echo "$_csrsubj" | tr '*' '#')"
_debug _escapedSubject "$_escapedSubject"
_dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")"
_debug _dnsAltnames "$_dnsAltnames"
else
_debug "AltNames doesn't contain subject"
fi
printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
echo "$_dnsAltnames" | sed "s/DNS://g"
}
#_csrfile
......@@ -1181,7 +1193,7 @@ _ss() {
if _exists "netstat"; then
_debug "Using: netstat"
if netstat -h 2>&1 | grep "\-p proto" >/dev/null; then
if netstat -help 2>&1 | grep "\-p proto" >/dev/null; then
#for windows version netstat tool
netstat -an -p tcp | grep "LISTENING" | grep ":$_port "
else
......@@ -1327,6 +1339,7 @@ createDomainKey() {
if _createkey "$_cdl" "$CERT_KEY_PATH"; then
_savedomainconf Le_Keylength "$_cdl"
_info "The domain key is here: $(__green $CERT_KEY_PATH)"
return 0
fi
else
if [ "$IS_RENEW" ]; then
......@@ -1374,17 +1387,17 @@ _url_replace() {
}
_time2str() {
#Linux
if date -u -d@"$1" 2>/dev/null; then
#BSD
if date -u -r "$1" 2>/dev/null; then
return
fi
#BSD
if date -u -r "$1" 2>/dev/null; then
#Linux
if date -u -d@"$1" 2>/dev/null; then
return
fi
#Soaris
#Solaris
if _exists adb; then
_t_s_a=$(echo "0t${1}=Y" | adb)
echo "$_t_s_a"
......@@ -1519,7 +1532,8 @@ _calcjwk() {
JWK_HEADERPLACE_PART1='{"nonce": "'
JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
else
_err "Only RSA or EC key is supported."
_err "Only RSA or EC key is supported. keyfile=$keyfile"
_debug2 "$(cat "$keyfile")"
return 1
fi
......@@ -1607,7 +1621,7 @@ _inithttp() {
}
# body url [needbase64] [POST|PUT] [ContentType]
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
_post() {
body="$1"
_post_url="$2"
......@@ -1795,29 +1809,28 @@ _send_signed_request() {
return 1
fi
if [ "$ACME_VERSION" = "2" ]; then
__request_conent_type="$CONTENT_TYPE_JSON"
else
__request_conent_type=""
fi
__request_conent_type="$CONTENT_TYPE_JSON"
payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
_debug3 payload64 "$payload64"
MAX_REQUEST_RETRY_TIMES=5
MAX_REQUEST_RETRY_TIMES=20
_sleep_retry_sec=1
_request_retry_times=0
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do
_request_retry_times=$(_math "$_request_retry_times" + 1)
_debug3 _request_retry_times "$_request_retry_times"
if [ -z "$_CACHED_NONCE" ]; then
_headers=""
if [ "$ACME_NEW_NONCE" ]; then
_debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
_debug2 "Get nonce with HEAD. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
nonceurl="$ACME_NEW_NONCE"
if _post "" "$nonceurl" "" "HEAD" "$__request_conent_type"; then
_headers="$(cat "$HTTP_HEADER")"
fi
fi
if [ -z "$_headers" ]; then
_debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY"
_debug2 "Get nonce with GET. ACME_DIRECTORY" "$ACME_DIRECTORY"
nonceurl="$ACME_DIRECTORY"
_headers="$(_get "$nonceurl" "onlyheader")"
fi
......@@ -1836,7 +1849,11 @@ _send_signed_request() {
fi
nonce="$_CACHED_NONCE"
_debug2 nonce "$nonce"
if [ -z "$nonce" ]; then
_info "Could not get nonce, let's try again."
_sleep 2
continue
fi
if [ "$ACME_VERSION" = "2" ]; then
if [ "$url" = "$ACME_NEW_ACCOUNT" ] || [ "$url" = "$ACME_REVOKE_CERT" ]; then
protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
......@@ -1860,11 +1877,7 @@ _send_signed_request() {
sig="$(printf "%s" "$_sig_t" | _url_replace)"
_debug3 sig "$sig"
if [ "$ACME_VERSION" = "2" ]; then
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
else
body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
fi
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
_debug3 body "$body"
response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
......@@ -1874,29 +1887,34 @@ _send_signed_request() {
_err "Can not post to $url"
return 1
fi
_debug2 original "$response"
response="$(echo "$response" | _normalizeJson)"
responseHeaders="$(cat "$HTTP_HEADER")"
_debug2 responseHeaders "$responseHeaders"
_debug2 response "$response"
code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
_debug code "$code"
_CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
_body="$response"
if [ "$needbase64" ]; then
_body="$(echo "$_body" | _dbase64 | tr -d '\0')"
_debug3 _body "$_body"
_debug2 original "$response"
if echo "$responseHeaders" | grep -i "Content-Type: application/json" >/dev/null 2>&1; then
response="$(echo "$response" | _normalizeJson)"
fi
_debug2 response "$response"
if _contains "$_body" "JWS has invalid anti-replay nonce"; then
_info "It seems the CA server is busy now, let's wait and retry."
_request_retry_times=$(_math "$_request_retry_times" + 1)
_sleep 5
continue
_CACHED_NONCE="$(echo "$responseHeaders" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
if ! _startswith "$code" "2"; then
_body="$response"
if [ "$needbase64" ]; then
_body="$(echo "$_body" | _dbase64 multiline)"
_debug3 _body "$_body"
fi
if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then
_info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds."
_CACHED_NONCE=""
_sleep $_sleep_retry_sec
continue
fi
fi
break
done
......@@ -2101,7 +2119,7 @@ _sleep() {
fi
}
# _starttlsserver san_a san_b port content _ncaddr
# _starttlsserver san_a san_b port content _ncaddr acmeValidationv1
_starttlsserver() {
_info "Starting tls server."
san_a="$1"
......@@ -2109,10 +2127,12 @@ _starttlsserver() {
port="$3"
content="$4"
opaddr="$5"
acmeValidationv1="$6"
_debug san_a "$san_a"
_debug san_b "$san_b"
_debug port "$port"
_debug acmeValidationv1 "$acmeValidationv1"
#create key TLS_KEY
if ! _createkey "2048" "$TLS_KEY"; then
......@@ -2125,7 +2145,7 @@ _starttlsserver() {
if [ "$san_b" ]; then
alt="$alt,$san_b"
fi
if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then
if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then
_err "Create tls validation csr error."
return 1
fi
......@@ -2151,6 +2171,10 @@ _starttlsserver() {
__S_OPENSSL="$__S_OPENSSL -6"
fi
if [ "$acmeValidationv1" ]; then
__S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1"
fi
_debug "$__S_OPENSSL"
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
$__S_OPENSSL -tlsextdebug &
......@@ -2839,7 +2863,7 @@ _isRealNginxConf() {
_skip_ssl=1
for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do
if [ "$_listen_i" ]; then
if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl[ |;]")" ]; then
if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl")" ]; then
_debug2 "$_listen_i is ssl"
else
_debug2 "$_listen_i is plain text"
......@@ -2905,38 +2929,38 @@ _clearup() {
_clearupdns() {
_debug "_clearupdns"
if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then
_debug "dns_entries" "$dns_entries"
if [ -z "$dns_entries" ]; then
_debug "skip dns."
return
fi
_info "Removing DNS records."
ventries=$(echo "$vlist" | tr ',' ' ')
_alias_index=1
for ventry in $ventries; do
d=$(echo "$ventry" | cut -d "$sep" -f 1)
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
_debug txt "$txt"
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
_debug "$d is already verified, skip $vtype."
continue
fi
if [ "$vtype" != "$VTYPE_DNS" ]; then
_debug "Skip $d for $vtype"
continue
for entry in $dns_entries; do
d=$(_getfield "$entry" 1)
txtdomain=$(_getfield "$entry" 2)
aliasDomain=$(_getfield "$entry" 3)
txt=$(_getfield "$entry" 5)
d_api=$(_getfield "$entry" 6)
_debug "d" "$d"
_debug "txtdomain" "$txtdomain"
_debug "aliasDomain" "$aliasDomain"
_debug "txt" "$txt"
_debug "d_api" "$d_api"
if [ "$d_api" = "$txt" ]; then
d_api=""
fi
d_api="$(_findHook "$d" dnsapi "$_currentRoot")"
_debug d_api "$d_api"
if [ -z "$d_api" ]; then
_info "Not Found domain api file: $d_api"
continue
fi
if [ "$aliasDomain" ]; then
txtdomain="$aliasDomain"
fi
(
if ! . "$d_api"; then
_err "Load file $d_api error. Please check your api file and try again."
......@@ -2949,24 +2973,6 @@ _clearupdns() {
return 1
fi
_dns_root_d="$d"
if _startswith "$_dns_root_d" "*."; then
_dns_root_d="$(echo "$_dns_root_d" | sed 's/*.//')"
fi
_d_alias="$(_getfield "$_challenge_alias" "$_alias_index")"
_alias_index="$(_math "$_alias_index" + 1)"
_debug "_d_alias" "$_d_alias"
if [ "$_d_alias" ]; then
if _startswith "$_d_alias" "$DNS_ALIAS_PREFIX"; then
txtdomain="$(echo "$_d_alias" | sed "s/$DNS_ALIAS_PREFIX//")"
else
txtdomain="_acme-challenge.$_d_alias"
fi
else
txtdomain="_acme-challenge.$_dns_root_d"
fi
if ! $rmcommand "$txtdomain" "$txt"; then
_err "Error removing txt for domain:$txtdomain"
return 1
......@@ -3060,8 +3066,8 @@ _on_before_issue() {
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
fi
_checkport="$Le_HTTPPort"
elif [ "$_currentRoot" = "$W_TLS" ]; then
_info "Standalone tls mode."
elif [ "$_currentRoot" = "$W_ALPN" ]; then
_info "Standalone alpn mode."
if [ -z "$Le_TLSPort" ]; then
Le_TLSPort=443
else
......@@ -3421,18 +3427,127 @@ __get_domain_new_authz() {
#uri keyAuthorization
__trigger_validation() {
_debug2 "tigger domain validation."
_debug2 "Trigger domain validation."
_t_url="$1"
_debug2 _t_url "$_t_url"
_t_key_authz="$2"
_debug2 _t_key_authz "$_t_key_authz"
_t_vtype="$3"
_debug2 _t_vtype "$_t_vtype"
if [ "$ACME_VERSION" = "2" ]; then
_send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}"
else
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"type\": \"$_t_vtype\", \"keyAuthorization\": \"$_t_key_authz\"}"
fi
}
#endpoint domain type
_ns_lookup() {
_ns_ep="$1"
_ns_domain="$2"
_ns_type="$3"
_debug2 "_ns_ep" "$_ns_ep"
_debug2 "_ns_domain" "$_ns_domain"
_debug2 "_ns_type" "$_ns_type"
response="$(_H1="accept: application/dns-json" _get "$_ns_ep?name=$_ns_domain&type=$_ns_type")"
_ret=$?
_debug2 "response" "$response"
if [ "$_ret" != "0" ]; then
return $_ret
fi
_answers="$(echo "$response" | tr '{}' '<>' | _egrep_o '"Answer":\[[^]]*]' | tr '<>' '\n\n')"
_debug2 "_answers" "$_answers"
echo "$_answers"
}
#domain, type
_ns_lookup_cf() {
_cf_ld="$1"
_cf_ld_type="$2"
_cf_ep="https://cloudflare-dns.com/dns-query"
_ns_lookup "$_cf_ep" "$_cf_ld" "$_cf_ld_type"
}
#domain, type
_ns_purge_cf() {
_cf_d="$1"
_cf_d_type="$2"
_debug "Cloudflare purge $_cf_d_type record for domain $_cf_d"
_cf_purl="https://1.1.1.1/api/v1/purge?domain=$_cf_d&type=$_cf_d_type"
response="$(_post "" "$_cf_purl")"
_debug2 response "$response"
}
#txtdomain, alias, txt
__check_txt() {
_c_txtdomain="$1"
_c_aliasdomain="$2"
_c_txt="$3"
_debug "_c_txtdomain" "$_c_txtdomain"
_debug "_c_aliasdomain" "$_c_aliasdomain"
_debug "_c_txt" "$_c_txt"
_answers="$(_ns_lookup_cf "$_c_aliasdomain" TXT)"
_contains "$_answers" "$_c_txt"
}
#txtdomain
__purge_txt() {
_p_txtdomain="$1"
_debug _p_txtdomain "$_p_txtdomain"
_ns_purge_cf "$_p_txtdomain" "TXT"
}
#wait and check each dns entries
_check_dns_entries() {
_success_txt=","
_end_time="$(_time)"
_end_time="$(_math "$_end_time" + 1200)" #let's check no more than 20 minutes.
while [ "$(_time)" -le "$_end_time" ]; do
_left=""
for entry in $dns_entries; do
d=$(_getfield "$entry" 1)
txtdomain=$(_getfield "$entry" 2)
aliasDomain=$(_getfield "$entry" 3)
txt=$(_getfield "$entry" 5)
d_api=$(_getfield "$entry" 6)
_debug "d" "$d"
_debug "txtdomain" "$txtdomain"
_debug "aliasDomain" "$aliasDomain"
_debug "txt" "$txt"
_debug "d_api" "$d_api"
_info "Checking $d for $aliasDomain"
if _contains "$_success_txt" ",$txt,"; then
_info "Already success, continue next one."
continue
fi
if __check_txt "$txtdomain" "$aliasDomain" "$txt"; then
_info "Domain $d '$aliasDomain' success."
_success_txt="$_success_txt,$txt,"
continue
fi
_left=1
_info "Not valid yet, let's wait 10 seconds and check next one."
_sleep 10
__purge_txt "$txtdomain"
if [ "$txtdomain" != "$aliasDomain" ]; then
__purge_txt "$aliasDomain"
fi
done
if [ "$_left" ]; then
_info "Let's wait 10 seconds and check again".
_sleep 10
else
_info "All success, let's return"
break
fi
done
}
#webroot, domain domainlist keylength
issue() {
if [ -z "$2" ]; then
......@@ -3632,7 +3747,7 @@ issue() {
_authorizations_map=""
for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' '); do
_debug2 "_authz_url" "$_authz_url"
if ! response="$(_get "$_authz_url")"; then
if ! _send_signed_request "$_authz_url"; then
_err "get to authz error."
_err "_authorizations_seg" "$_authorizations_seg"
_err "_authz_url" "$_authz_url"
......@@ -3679,12 +3794,8 @@ $_authorizations_map"
vtype="$VTYPE_DNS"
fi
if [ "$_currentRoot" = "$W_TLS" ]; then
if [ "$ACME_VERSION" = "2" ]; then
vtype="$VTYPE_TLS2"
else
vtype="$VTYPE_TLS"
fi
if [ "$_currentRoot" = "$W_ALPN" ]; then
vtype="$VTYPE_ALPN"
fi
if [ "$ACME_VERSION" = "2" ]; then
......@@ -3760,6 +3871,7 @@ $_authorizations_map"
done
_debug vlist "$vlist"
#add entry
dns_entries=""
dnsadded=""
ventries=$(echo "$vlist" | tr "$dvsep" ' ')
_alias_index=1
......@@ -3771,6 +3883,7 @@ $_authorizations_map"
_debug d "$d"
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
_debug "$d is already verified, skip $vtype."
_alias_index="$(_math "$_alias_index" + 1)"
continue
fi
......@@ -3789,8 +3902,10 @@ $_authorizations_map"
else
txtdomain="_acme-challenge.$_d_alias"
fi
dns_entries="${dns_entries}${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$txtdomain$dvsep$_currentRoot"
else
txtdomain="_acme-challenge.$_dns_root_d"
dns_entries="${dns_entries}${_dns_root_d}${dvsep}_acme-challenge.$_dns_root_d$dvsep$dvsep$_currentRoot"
fi
_debug txtdomain "$txtdomain"
txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
......@@ -3799,7 +3914,9 @@ $_authorizations_map"
d_api="$(_findHook "$_dns_root_d" dnsapi "$_currentRoot")"
_debug d_api "$d_api"
dns_entries="$dns_entries$dvsep$txt${dvsep}$d_api
"
_debug2 "$dns_entries"
if [ "$d_api" ]; then
_info "Found domain api file: $d_api"
else
......@@ -3834,8 +3951,8 @@ $_authorizations_map"
)
if [ "$?" != "0" ]; then
_clearup
_on_issue_err "$_post_hook" "$vlist"
_clearup
return 1
fi
dnsadded='1'
......@@ -3846,22 +3963,28 @@ $_authorizations_map"
_savedomainconf "Le_Vlist" "$vlist"
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
_err "Please add the TXT records to the domains, and re-run with --renew."
_clearup
_on_issue_err "$_post_hook"
_clearup
return 1
fi
fi
if [ "$dnsadded" = '1' ]; then
if [ "$dns_entries" ]; then
if [ -z "$Le_DNSSleep" ]; then
Le_DNSSleep="$DEFAULT_DNS_SLEEP"
_info "Let's check each dns records now. Sleep 20 seconds first."
_sleep 20
if ! _check_dns_entries; then
_err "check dns error."
_on_issue_err "$_post_hook"
_clearup
return 1
fi
else
_savedomainconf "Le_DNSSleep" "$Le_DNSSleep"
_info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect"
_sleep "$Le_DNSSleep"
fi
_info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect"
_sleep "$Le_DNSSleep"
fi
NGINX_RESTORE_VLIST=""
......@@ -3881,7 +4004,7 @@ $_authorizations_map"
continue
fi
_info "Verifying:$d"
_info "Verifying: $d"
_debug "d" "$d"
_debug "keyauthorization" "$keyauthorization"
_debug "uri" "$uri"
......@@ -3965,34 +4088,10 @@ $_authorizations_map"
fi
fi
elif [ "$vtype" = "$VTYPE_TLS" ]; then
#create A
#_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )"
#_debug2 _hash_A "$_hash_A"
#_x="$(echo $_hash_A | cut -c 1-32)"
#_debug2 _x "$_x"
#_y="$(echo $_hash_A | cut -c 33-64)"
#_debug2 _y "$_y"
#_SAN_A="$_x.$_y.token.acme.invalid"
#_debug2 _SAN_A "$_SAN_A"
#create B
_hash_B="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
_debug2 _hash_B "$_hash_B"
_x="$(echo "$_hash_B" | cut -c 1-32)"
_debug2 _x "$_x"
_y="$(echo "$_hash_B" | cut -c 33-64)"
_debug2 _y "$_y"
#_SAN_B="$_x.$_y.ka.acme.invalid"
_SAN_B="$_x.$_y.acme.invalid"
_debug2 _SAN_B "$_SAN_B"
_ncaddr="$(_getfield "$_local_addr" "$_ncIndex")"
_ncIndex="$(_math "$_ncIndex" + 1)"
if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then
elif [ "$vtype" = "$VTYPE_ALPN" ]; then
acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
_debug acmevalidationv1 "$acmevalidationv1"
if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then
_err "Start tls server error."
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
......@@ -4001,7 +4100,7 @@ $_authorizations_map"
fi
fi
if ! __trigger_validation "$uri" "$keyauthorization"; then
if ! __trigger_validation "$uri" "$keyauthorization" "$vtype"; then
_err "$d:Can not get challenge: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
......@@ -4010,7 +4109,7 @@ $_authorizations_map"
fi
if [ "$code" ] && [ "$code" != '202' ]; then
if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then
if [ "$code" = '200' ]; then
_debug "trigger validation code: $code"
else
_err "$d:Challenge error: $response"
......@@ -4039,7 +4138,11 @@ $_authorizations_map"
_debug "sleep 2 secs to verify"
sleep 2
_debug "checking"
response="$(_get "$uri")"
if [ "$ACME_VERSION" = "2" ]; then
_send_signed_request "$uri"
else
response="$(_get "$uri")"
fi
if [ "$?" != "0" ]; then
_err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
......@@ -4115,13 +4218,16 @@ $_authorizations_map"
fi
Le_LinkCert="$(echo "$response" | tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
if ! _get "$Le_LinkCert" >"$CERT_PATH"; then
_tempSignedResponse="$response"
if ! _send_signed_request "$Le_LinkCert"; then
_err "Sign failed, can not download cert:$Le_LinkCert."
_err "$response"
_on_issue_err "$_post_hook"
return 1
fi
echo "$response" >"$CERT_PATH"
if [ "$(grep -- "$BEGIN_CERT" "$CERT_PATH" | wc -l)" -gt "1" ]; then
_debug "Found cert chain"
cat "$CERT_PATH" >"$CERT_FULLCHAIN_PATH"
......@@ -4131,6 +4237,7 @@ $_authorizations_map"
_end_n="$(_math $_end_n + 1)"
sed -n "${_end_n},9999p" "$CERT_FULLCHAIN_PATH" >"$CA_CERT_PATH"
fi
response="$_tempSignedResponse"
else
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
_err "Sign failed. $response"
......@@ -4201,7 +4308,8 @@ $_authorizations_map"
while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do
_debug _link_issuer_retry "$_link_issuer_retry"
if [ "$ACME_VERSION" = "2" ]; then
if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then
if _send_signed_request "$Le_LinkIssuer"; then
echo "$response" >"$CA_CERT_PATH"
break
fi
else
......@@ -4237,8 +4345,8 @@ $_authorizations_map"
Le_CertCreateTimeStr=$(date -u)
_savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then
Le_RenewalDays="$MAX_RENEW"
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then
Le_RenewalDays="$DEFAULT_RENEW"
else
_savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
fi
......@@ -4283,20 +4391,21 @@ $_authorizations_map"
Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
_savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
if ! _on_issue_success "$_post_hook" "$_renew_hook"; then
_err "Call hook error."
return 1
fi
if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then
_savedomainconf "Le_RealCertPath" "$_real_cert"
_savedomainconf "Le_RealCACertPath" "$_real_ca"
_savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd"
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"
if ! _installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"; then
return 1
fi
fi
if ! _on_issue_success "$_post_hook" "$_renew_hook"; then
_err "Call hook error."
return 1
fi
}
#domain [isEcc]
......@@ -4597,7 +4706,8 @@ deploy() {
_initpath "$_d" "$_isEcc"
if [ ! -d "$DOMAIN_PATH" ]; then
_err "Domain is not valid:'$_d'"
_err "The domain '$_d' is not a cert name. You must use the cert name to specify the cert to install."
_err "Can not find path:'$DOMAIN_PATH'"
return 1
fi
......@@ -4624,7 +4734,8 @@ installcert() {
_initpath "$_main_domain" "$_isEcc"
if [ ! -d "$DOMAIN_PATH" ]; then
_err "Domain is not valid:'$_main_domain'"
_err "The domain '$_main_domain' is not a cert name. You must use the cert name to specify the cert to install."
_err "Can not find path:'$DOMAIN_PATH'"
return 1
fi
......@@ -4671,19 +4782,19 @@ _installcert() {
if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_cert" "$_backup_path/cert.bak"
fi
cat "$CERT_PATH" >"$_real_cert"
cat "$CERT_PATH" >"$_real_cert" || return 1
fi
if [ "$_real_ca" ]; then
_info "Installing CA to:$_real_ca"
if [ "$_real_ca" = "$_real_cert" ]; then
echo "" >>"$_real_ca"
cat "$CA_CERT_PATH" >>"$_real_ca"
cat "$CA_CERT_PATH" >>"$_real_ca" || return 1
else
if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_ca" "$_backup_path/ca.bak"
fi
cat "$CA_CERT_PATH" >"$_real_ca"
cat "$CA_CERT_PATH" >"$_real_ca" || return 1
fi
fi
......@@ -4693,9 +4804,9 @@ _installcert() {
cp "$_real_key" "$_backup_path/key.bak"
fi
if [ -f "$_real_key" ]; then
cat "$CERT_KEY_PATH" >"$_real_key"
cat "$CERT_KEY_PATH" >"$_real_key" || return 1
else
cat "$CERT_KEY_PATH" >"$_real_key"
cat "$CERT_KEY_PATH" >"$_real_key" || return 1
chmod 600 "$_real_key"
fi
fi
......@@ -4705,7 +4816,7 @@ _installcert() {
if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_fullchain" "$_backup_path/fullchain.bak"
fi
cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain"
cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain" || return 1
fi
if [ "$_reload_cmd" ]; then
......@@ -4924,7 +5035,7 @@ _deactivate() {
authzUri="$_authorizations_seg"
_debug2 "authzUri" "$authzUri"
if ! response="$(_get "$authzUri")"; then
if ! _send_signed_request "$authzUri"; then
_err "get to authz error."
_err "_authorizations_seg" "$_authorizations_seg"
_err "authzUri" "$authzUri"
......@@ -5458,6 +5569,7 @@ Parameters:
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure.
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode.
--alpn Use standalone alpn mode.
--stateless Use stateless mode, see: $_STATELESS_WIKI
--apache Use apache mode.
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
......@@ -5469,7 +5581,7 @@ Parameters:
--log-level 1|2 Specifies the log level, default is 1.
--syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert:
--cert-file After issue/renew, the cert will be copied to this path.
--key-file After issue/renew, the key will be copied to this path.
......@@ -5480,14 +5592,15 @@ Parameters:
--server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory)
--accountconf Specifies a customized account config file.
--home Specifies the home dir for $PROJECT_NAME .
--home Specifies the home dir for $PROJECT_NAME.
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
--config-home Specifies the home dir to save all the configurations.
--useragent Specifies the user agent string. it will be saved for future use too.
--accountemail Specifies the account email, only valid for the '--install' and '--update-account' command.
--accountkey Specifies the account key path, only valid for the '--install' command.
--days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
--days Specifies the days to renew the cert when using '--issue' command. The default value is $DEFAULT_RENEW days.
--httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
--tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
--local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
--listraw Only used for '--list' command, list the certs in raw format.
--stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
......@@ -5496,6 +5609,7 @@ Parameters:
--ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl.
--nocron Only valid for '--install' command, which means: do not install the default cron job. In this case, the certs will not be renewed automatically.
--no-color Do not output color text.
--force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails.
--ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
--csr Specifies the input csr.
--pre-hook Command to be run before obtaining any certificates.
......@@ -5510,6 +5624,7 @@ Parameters:
--openssl-bin Specifies a custom openssl bin location.
--use-wget Force to use wget, if you have both curl and wget installed.
--yes-I-know-dns-manual-mode-enough-go-ahead-please Force to use dns manual mode: $_DNS_MANUAL_WIKI
--branch, -b Only valid for '--upgrade' command, specifies the branch name to upgrade to.
"
}
......@@ -5810,6 +5925,14 @@ _process() {
_webroot="$_webroot,$wvalue"
fi
;;
--alpn)
wvalue="$W_ALPN"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--stateless)
wvalue="$MODE_STATELESS"
if [ -z "$_webroot" ]; then
......@@ -5934,6 +6057,11 @@ _process() {
Le_HTTPPort="$_httpport"
shift
;;
--tlsport)
_tlsport="$2"
Le_TLSPort="$_tlsport"
shift
;;
--listraw)
_listraw="raw"
;;
......@@ -5960,6 +6088,9 @@ _process() {
--no-color)
export ACME_NO_COLOR=1
;;
--force-color)
export ACME_FORCE_COLOR=1
;;
--ecc)
_ecc="isEcc"
;;
......@@ -6054,6 +6185,10 @@ _process() {
_use_wget="1"
ACME_USE_WGET="1"
;;
--branch | -b)
export BRANCH="$2"
shift
;;
*)
_err "Unknown parameter : $1"
return 1
......
......@@ -256,7 +256,143 @@ acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox
acme.sh --deploy -d ftp.example.com --deploy-hook strongswan
```
## 10. Deploy the cert to remote routeros
## 10. Deploy the cert to HAProxy
You must specify the path where you want the concatenated key and certificate chain written.
```sh
export DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy
```
You may optionally define the command to reload HAProxy. The value shown below will be used as the default if you don't set this environment variable.
```sh
export DEPLOY_HAPROXY_RELOAD="/usr/sbin/service haproxy restart"
```
You can then deploy the certificate as follows
```sh
acme.sh --deploy -d haproxy.example.com --deploy-hook haproxy
```
The path for the PEM file will be stored with the domain configuration and will be available when renewing, so that deploy will happen automatically when renewed.
## 11. Deploy your cert to Gitlab pages
You must define the API key and the informations for the project and Gitlab page you are updating the certificate for.
```sh
# The token can be created in your user settings under "Access Tokens"
export GITLAB_TOKEN="xxxxxxxxxxx"
# The project ID is displayed on the home page of the project
export GITLAB_PROJECT_ID=12345678
# The domain must match the one defined for the Gitlab page, without "https://"
export GITLAB_DOMAIN="www.mydomain.com"
```
You can then deploy the certificate as follows
```sh
acme.sh --deploy -d www.mydomain.com --deploy-hook gitlab
```
## 12. Deploy your cert to Hashicorp Vault
```sh
export VAULT_PREFIX="acme"
```
You can then deploy the certificate as follows
```sh
acme.sh --deploy -d www.mydomain.com --deploy-hook vault_cli
```
Your certs will be saved in Vault using this structure:
```sh
vault write "${VAULT_PREFIX}/${domain}/cert.pem" value=@"..."
vault write "${VAULT_PREFIX}/${domain}/cert.key" value=@"..."
vault write "${VAULT_PREFIX}/${domain}/chain.pem" value=@"..."
vault write "${VAULT_PREFIX}/${domain}/fullchain.pem" value=@"..."
```
You might be using Fabio load balancer (which can get certs from
Vault). It needs a bit different structure of your certs in Vault. It
gets certs only from keys that were saved in `prefix/domain`, like this:
```bash
vault write <PREFIX>/www.domain.com cert=@cert.pem key=@key.pem
```
If you want to save certs in Vault this way just set "FABIO" env
variable to anything (ex: "1") before running `acme.sh`:
```sh
export FABIO="1"
```
## 13. Deploy your certificate to Qiniu.com
使用 acme.sh 部署到七牛之前,需要确保部署的域名已打开 HTTPS 功能,您可以访问[融合 CDN - 域名管理](https://portal.qiniu.com/cdn/domain) 设置。
另外还需要先导出 AK/SK 环境变量,您可以访问[密钥管理](https://portal.qiniu.com/user/key) 获得。
```sh
$ export QINIU_AK="foo"
$ export QINIU_SK="bar"
```
完成准备工作之后,您就可以通过下面的命令开始部署 SSL 证书到七牛上:
```sh
$ acme.sh --deploy -d example.com --deploy-hook qiniu
```
假如您部署的证书为泛域名证书,您还需要设置 `QINIU_CDN_DOMAIN` 变量,指定实际需要部署的域名:
```sh
$ export QINIU_CDN_DOMAIN="cdn.example.com"
$ acme.sh --deploy -d example.com --deploy-hook qiniu
```
### English version
You should create AccessKey/SecretKey pair in https://portal.qiniu.com/user/key
before deploying your certificate, and please ensure you have enabled HTTPS for
your domain name. You can enable it in https://portal.qiniu.com/cdn/domain.
```sh
$ export QINIU_AK="foo"
$ export QINIU_SK="bar"
```
then you can deploy certificate by following command:
```sh
$ acme.sh --deploy -d example.com --deploy-hook qiniu
```
(Optional), If you are using wildcard certificate,
you may need export `QINIU_CDN_DOMAIN` to specify which domain
you want to update:
```sh
$ export QINIU_CDN_DOMAIN="cdn.example.com"
$ acme.sh --deploy -d example.com --deploy-hook qiniu
```
## 14. Deploy your cert on MyDevil.net
Once you have acme.sh installed and certificate issued (see info in [DNS API](../dnsapi/README.md#61-use-mydevilnet)), you can install it by following command:
```sh
acme.sh --deploy --deploy-hook mydevil -d example.com
```
That will remove old certificate and install new one.
## 15. Deploy the cert to remote routeros
```sh
acme.sh --deploy -d ftp.example.com --deploy-hook routeros
......
......@@ -2,8 +2,12 @@
# Here is the script to deploy the cert to your cpanel using the cpanel API.
# Uses command line uapi. --user option is needed only if run as root.
# Returns 0 when success.
# Written by Santeri Kannisto <santeri.kannisto@2globalnomads.info>
# Public domain, 2017
#
# Please note that I am no longer using Github. If you want to report an issue
# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/
#
# Written by Santeri Kannisto <santeri.kannisto@webseodesigners.com>
# Public domain, 2017-2018
#export DEPLOY_CPANEL_USER=myusername
......@@ -28,15 +32,9 @@ cpanel_uapi_deploy() {
_err "The command uapi is not found."
return 1
fi
if ! _exists php; then
_err "The command php is not found."
return 1
fi
# read cert and key files and urlencode both
_certstr=$(cat "$_ccert")
_keystr=$(cat "$_ckey")
_cert=$(php -r "echo urlencode(\"$_certstr\");")
_key=$(php -r "echo urlencode(\"$_keystr\");")
_cert=$(_url_encode <"$_ccert")
_key=$(_url_encode <"$_ckey")
_debug _cert "$_cert"
_debug _key "$_key"
......
......@@ -28,8 +28,10 @@ fritzbox_deploy() {
_debug _cfullchain "$_cfullchain"
if ! _exists iconv; then
_err "iconv not found"
return 1
if ! _exists perl; then
_err "iconv or perl not found"
return 1
fi
fi
_fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}"
......@@ -61,7 +63,11 @@ fritzbox_deploy() {
_info "Log in to the FRITZ!Box"
_fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')"
if _exists iconv; then
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')"
else
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | md5sum | awk '{print $1}')"
fi
_fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then
......
#!/usr/bin/env sh
# Script to deploy certificate to a Gitlab hosted page
# The following variables exported from environment will be used.
# If not set then values previously saved in domain.conf file are used.
# All the variables are required
# export GITLAB_TOKEN="xxxxxxx"
# export GITLAB_PROJECT_ID=012345
# export GITLAB_DOMAIN="mydomain.com"
gitlab_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
if [ -z "$GITLAB_TOKEN" ]; then
if [ -z "$Le_Deploy_gitlab_token" ]; then
_err "GITLAB_TOKEN not defined."
return 1
fi
else
Le_Deploy_gitlab_token="$GITLAB_TOKEN"
_savedomainconf Le_Deploy_gitlab_token "$Le_Deploy_gitlab_token"
fi
if [ -z "$GITLAB_PROJECT_ID" ]; then
if [ -z "$Le_Deploy_gitlab_project_id" ]; then
_err "GITLAB_PROJECT_ID not defined."
return 1
fi
else
Le_Deploy_gitlab_project_id="$GITLAB_PROJECT_ID"
_savedomainconf Le_Deploy_gitlab_project_id "$Le_Deploy_gitlab_project_id"
fi
if [ -z "$GITLAB_DOMAIN" ]; then
if [ -z "$Le_Deploy_gitlab_domain" ]; then
_err "GITLAB_DOMAIN not defined."
return 1
fi
else
Le_Deploy_gitlab_domain="$GITLAB_DOMAIN"
_savedomainconf Le_Deploy_gitlab_domain "$Le_Deploy_gitlab_domain"
fi
string_fullchain=$(_url_encode <"$_cfullchain")
string_key=$(_url_encode <"$_ckey")
body="certificate=$string_fullchain&key=$string_key"
export _H1="PRIVATE-TOKEN: $Le_Deploy_gitlab_token"
gitlab_url="https://gitlab.com/api/v4/projects/$Le_Deploy_gitlab_project_id/pages/domains/$Le_Deploy_gitlab_domain"
_response=$(_post "$body" "$gitlab_url" 0 PUT | _dbase64 "multiline")
error_response="error"
if test "${_response#*$error_response}" != "$_response"; then
_err "Error in deploying certificate:"
_err "$_response"
return 1
fi
_debug response "$_response"
_info "Certificate successfully deployed"
return 0
}
......@@ -20,7 +20,39 @@ haproxy_deploy() {
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to haproxy server, Not implemented yet"
return 1
# handle reload preference
DEFAULT_HAPROXY_RELOAD="/usr/sbin/service haproxy restart"
if [ -z "${DEPLOY_HAPROXY_RELOAD}" ]; then
_reload="${DEFAULT_HAPROXY_RELOAD}"
_cleardomainconf DEPLOY_HAPROXY_RELOAD
else
_reload="${DEPLOY_HAPROXY_RELOAD}"
_savedomainconf DEPLOY_HAPROXY_RELOAD "$DEPLOY_HAPROXY_RELOAD"
fi
_savedomainconf DEPLOY_HAPROXY_PEM_PATH "$DEPLOY_HAPROXY_PEM_PATH"
# work out the path where the PEM file should go
_pem_path="${DEPLOY_HAPROXY_PEM_PATH}"
if [ -z "$_pem_path" ]; then
_err "Path to save PEM file not found. Please define DEPLOY_HAPROXY_PEM_PATH."
return 1
fi
_pem_full_path="$_pem_path/$_cdomain.pem"
_info "Full path to PEM $_pem_full_path"
# combine the key and fullchain into a single pem and install
cat "$_cfullchain" "$_ckey" >"$_pem_full_path"
chmod 600 "$_pem_full_path"
_info "Certificate successfully deployed"
# restart HAProxy
_info "Run reload: $_reload"
if eval "$_reload"; then
_info "Reload success!"
return 0
else
_err "Reload error"
return 1
fi
}
#!/usr/bin/env sh
#Here is a sample custom api script.
#This file name is "myapi.sh"
#So, here must be a method myapi_deploy()
#Which will be called by acme.sh to deploy the cert
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
......
#!/usr/bin/env sh
# MyDevil.net API (2019-02-03)
#
# MyDevil.net already supports automatic Let's Encrypt certificates,
# except for wildcard domains.
#
# This script depends on `devil` command that MyDevil.net provides,
# which means that it works only on server side.
#
# Author: Marcin Konicki <https://ahwayakchih.neoni.net>
#
######## Public functions #####################
# Usage: mydevil_deploy domain keyfile certfile cafile fullchain
mydevil_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
ip=""
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
if ! _exists "devil"; then
_err "Could not find 'devil' command."
return 1
fi
ip=$(mydevil_get_ip "$_cdomain")
if [ -z "$ip" ]; then
_err "Could not find IP for domain $_cdomain."
return 1
fi
# Delete old certificate first
_info "Removing old certificate for $_cdomain at $ip"
devil ssl www del "$ip" "$_cdomain"
# Add new certificate
_info "Adding new certificate for $_cdomain at $ip"
devil ssl www add "$ip" "$_cfullchain" "$_ckey" "$_cdomain" || return 1
return 0
}
#################### Private functions below ##################################
# Usage: ip=$(mydevil_get_ip domain.com)
# echo $ip
mydevil_get_ip() {
devil dns list "$1" | cut -w -s -f 3,7 | grep "^A$(printf '\t')" | cut -w -s -f 2 || return 1
return 0
}
#!/usr/bin/env sh
# Script to create certificate to qiniu.com
#
# This deployment required following variables
# export QINIU_AK="QINIUACCESSKEY"
# export QINIU_SK="QINIUSECRETKEY"
# export QINIU_CDN_DOMAIN="cdn.example.com"
QINIU_API_BASE="https://api.qiniu.com"
qiniu_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
if [ -z "$QINIU_AK" ]; then
_err "QINIU_AK is not defined."
return 1
else
_savedomainconf QINIU_AK "$QINIU_AK"
fi
if [ -z "$QINIU_SK" ]; then
_err "QINIU_SK is not defined."
return 1
else
_savedomainconf QINIU_SK "$QINIU_SK"
fi
if [ "$QINIU_CDN_DOMAIN" ]; then
_savedomainconf QINIU_CDN_DOMAIN "$QINIU_CDN_DOMAIN"
else
QINIU_CDN_DOMAIN="$_cdomain"
fi
## upload certificate
string_fullchain=$(sed 's/$/\\n/' "$_cfullchain" | tr -d '\n')
string_key=$(sed 's/$/\\n/' "$_ckey" | tr -d '\n')
sslcert_path="/sslcert"
sslcerl_body="{\"name\":\"$_cdomain\",\"common_name\":\"$QINIU_CDN_DOMAIN\",\"ca\":\"$string_fullchain\",\"pri\":\"$string_key\"}"
sslcert_access_token="$(_make_access_token "$sslcert_path")"
_debug sslcert_access_token "$sslcert_access_token"
export _H1="Authorization: QBox $sslcert_access_token"
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline")
if ! _contains "$sslcert_response" "certID"; then
_err "Error in creating certificate:"
_err "$sslcert_response"
return 1
fi
_debug sslcert_response "$sslcert_response"
_info "Certificate successfully uploaded, updating domain $_cdomain"
## extract certId
_certId="$(printf "%s" "$sslcert_response" | _normalizeJson | _egrep_o "certID\": *\"[^\"]*\"" | cut -d : -f 2)"
_debug certId "$_certId"
## update domain ssl config
update_path="/domain/$QINIU_CDN_DOMAIN/httpsconf"
update_body="{\"certid\":$_certId,\"forceHttps\":false}"
update_access_token="$(_make_access_token "$update_path")"
_debug update_access_token "$update_access_token"
export _H1="Authorization: QBox $update_access_token"
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
if _contains "$update_response" "error"; then
_err "Error in updating domain httpsconf:"
_err "$update_response"
return 1
fi
_debug update_response "$update_response"
_info "Certificate successfully deployed"
return 0
}
_make_access_token() {
_token="$(printf "%s\n" "$1" | _hmac "sha1" "$(printf "%s" "$QINIU_SK" | _hex_dump | tr -d " ")" | _base64)"
echo "$QINIU_AK:$_token"
}
......@@ -11,7 +11,7 @@
#
# Only a username is required. All others are optional.
#
# The following examples are for QNAP NAS running QTS 4.2
# The following examples are for QNAP NAS running QTS 4.2
# export DEPLOY_SSH_CMD="" # defaults to ssh
# export DEPLOY_SSH_USER="admin" # required
# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
......@@ -101,7 +101,7 @@ ssh_deploy() {
fi
# CERTFILE is optional.
# If provided then private key will be copied or appended to provided filename.
# If provided then certificate will be copied or appended to provided filename.
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
_savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
......@@ -190,7 +190,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
_info "Backup directories erased after 180 days."
fi
_debug "Remote commands to execute: $_cmdstr"
_secure_debug "Remote commands to execute: " "$_cmdstr"
_info "Submitting sequence of commands to remote server by ssh"
# quotations in bash cmd below intended. Squash travis spellcheck error
# shellcheck disable=SC2029
......
......@@ -49,8 +49,13 @@ vault_cli_deploy() {
return 1
fi
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
if [ -n "$FABIO" ]; then
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
else
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
$VAULT_CMD write "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
fi
}
# How to use DNS API
If your dns provider doesn't provide api access, you can use our dns alias mode:
https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode
## 1. Use CloudFlare domain API to automatically issue cert
First you need to login to your CloudFlare account to get your API key.
First you need to login to your CloudFlare account to get your [API key](https://dash.cloudflare.com/profile).
```
export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
......@@ -142,13 +146,17 @@ Finally, make the DNS server and update Key available to `acme.sh`
export NSUPDATE_SERVER="dns.example.com"
export NSUPDATE_KEY="/path/to/your/nsupdate.key"
```
and optionally (depending on DNS server)
```
export NSUPDATE_ZONE="example.com"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com
```
The `NSUPDATE_SERVER` and `NSUPDATE_KEY` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
The `NSUPDATE_SERVER`, `NSUPDATE_KEY`, and `NSUPDATE_ZONE` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 8. Use LuaDNS domain API
......@@ -259,16 +267,26 @@ when needed.
## 14. Use Linode domain API
The tokens created in the classic manager and cloud manager are incompatible
with one another. While the classic manager makes an all or nothing API, the
newer cloud manager interface promises to produce API keys with a finer
permission system. However, either way works just fine.
### Classic Manager ###
Classic Manager: https://manager.linode.com/profile/api
First you need to login to your Linode account to get your API Key.
[https://manager.linode.com/profile/api](https://manager.linode.com/profile/api)
Then add an API key with label *ACME* and copy the new key.
Then add an API key with label *ACME* and copy the new key into the following
command.
```sh
export LINODE_API_KEY="..."
```
Due to the reload time of any changes in the DNS records, we have to use the `dnssleep` option to wait at least 15 minutes for the changes to take effect.
Due to the reload time of any changes in the DNS records, we have to use the
`dnssleep` option to wait at least 15 minutes for the changes to take effect.
Ok, let's issue a cert now:
......@@ -276,7 +294,35 @@ Ok, let's issue a cert now:
acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com
```
The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
The `LINODE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be
reused when needed.
### Cloud Manager ###
Cloud Manager: https://cloud.linode.com/profile/tokens
First you need to login to your Linode account to get your API Key.
1. Click on "Add a Personal Access Token".
2. Give the new key a "Label" (we recommend *ACME*)
3. Give it Read/Write access to "Domains"
4. "Submit" and copy the new key into the `LINODE_V4_API_KEY` command below.
```sh
export LINODE_V4_API_KEY="..."
```
Due to the reload time of any changes in the DNS records, we have to use the
`dnssleep` option to wait at least 15 minutes for the changes to take effect.
Ok, let's issue a cert now:
```sh
acme.sh --issue --dns dns_linode_v4 --dnssleep 900 -d example.com -d www.example.com
```
The `LINODE_V4_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be
reused when needed.
## 15. Use FreeDNS
......@@ -325,6 +371,8 @@ The `CY_Username`, `CY_Password` and `CY_OTP_Secret` will be saved in `~/.acme.s
## 17. Use Domain-Offensive/Resellerinterface/Domainrobot API
ATTENTION: You need to be a registered Reseller to be able to use the ResellerInterface. As a normal user you can not use this method.
You will need your login credentials (Partner ID+Password) to the Resellerinterface, and export them before you run `acme.sh`:
```
export DO_PID="KD-1234567"
......@@ -448,7 +496,7 @@ The `Infoblox_Creds` and `Infoblox_Server` will be saved in `~/.acme.sh/account.
First you need to create/obtain API tokens on your [settings panel](https://vscale.io/panel/settings/tokens/).
```
VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
export VSCALE_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
```
Ok, let's issue a cert now:
......@@ -525,8 +573,9 @@ For issues, please report to https://github.com/raidenii/acme.sh/issues.
## 28. Use Name.com API
You'll need to fill out the form at https://www.name.com/reseller/apply to apply
for API username and token.
Create your API token here: https://www.name.com/account/settings/api
Note: `Namecom_Username` should be your Name.com username and not the token name. If you accidentally run the script with the token name as the username see `~/.acme.sh/account.conf` to fix the issue
```
export Namecom_Username="testuser"
......@@ -638,6 +687,14 @@ acme.sh --issue --dns dns_inwx -d example.com -d www.example.com
The `INWX_User` and `INWX_Password` settings will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
If your account is secured by mobile tan you have also defined the shared secret.
```
export INWX_Shared_Secret="shared secret"
```
You may need to re-enable the mobile tan to gain the shared secret.
## 34. User Servercow API v1
Create a new user from the servercow control center. Don't forget to activate **DNS API** for this user.
......@@ -750,7 +807,7 @@ DNS API keys may be created at https://panel.dreamhost.com/?tree=home.api.
Ensure the created key has add and remove privelages.
```
export DH_API_Key="<api key>"
export DH_API_KEY="<api key>"
acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com
```
......@@ -784,6 +841,443 @@ acme.sh --issue --dns dns_da -d example.com -d www.example.com
The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 42. Use KingHost DNS API
API access must be enabled at https://painel.kinghost.com.br/painel.api.php
```
export KINGHOST_Username="yourusername"
export KINGHOST_Password="yourpassword"
acme.sh --issue --dns dns_kinghost -d example.com -d *.example.com
```
The `KINGHOST_username` and `KINGHOST_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 43. Use Zilore DNS API
First, get your API key at https://my.zilore.com/account/api
```
export Zilore_Key="5dcad3a2-36cb-50e8-cb92-000002f9"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_zilore -d example.com -d *.example.com
```
The `Zilore_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 44. Use Loopia.se API
User must provide login credentials to the Loopia API.
The user needs the following permissions:
- addSubdomain
- updateZoneRecord
- getDomains
- removeSubdomain
Set the login credentials:
```
export LOOPIA_User="user@loopiaapi"
export LOOPIA_Password="password"
```
And to issue a cert:
```
acme.sh --issue --dns dns_loopia -d example.com -d *.example.com
```
The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 45. Use ACME DNS API
ACME DNS is a limited DNS server with RESTful HTTP API to handle ACME DNS challenges easily and securely.
https://github.com/joohoi/acme-dns
```
export ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update"
export ACMEDNS_USERNAME="<username>"
export ACMEDNS_PASSWORD="<password>"
export ACMEDNS_SUBDOMAIN="<subdomain>"
acme.sh --issue --dns dns_acmedns -d example.com -d www.example.com
```
The credentials will be saved in `~/.acme.sh/account.conf` and will
be reused when needed.
## 46. Use TELE3 API
First you need to login to your TELE3 account to set your API-KEY.
https://www.tele3.cz/system-acme-api.html
```
export TELE3_Key="MS2I4uPPaI..."
export TELE3_Secret="kjhOIHGJKHg"
acme.sh --issue --dns dns_tele3 -d example.com -d *.example.com
```
The TELE3_Key and TELE3_Secret will be saved in ~/.acme.sh/account.conf and will be reused when needed.
## 47. Use Euserv.eu API
First you need to login to your euserv.eu account and activate your API Administration (API Verwaltung).
[https://support.euserv.com](https://support.euserv.com)
Once you've activate, login to your API Admin Interface and create an API account.
Please specify the scope (active groups: domain) and assign the allowed IPs.
```
export EUSERV_Username="99999.user123"
export EUSERV_Password="Asbe54gHde"
```
Ok, let's issue a cert now: (Be aware to use the `--insecure` flag, cause euserv.eu is still using self-signed certificates!)
```
acme.sh --issue --dns dns_euserv -d example.com -d *.example.com --insecure
```
The `EUSERV_Username` and `EUSERV_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
Please report any issues to https://github.com/initit/acme.sh or to <github@initit.de>
## 48. Use DNSPod.com domain API to automatically issue cert
First you need to get your API Key and ID by this [get-the-user-token](https://www.dnspod.com/docs/info.html#get-the-user-token).
```
export DPI_Id="1234"
export DPI_Key="sADDsdasdgdsf"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_dpi -d example.com -d www.example.com
```
The `DPI_Id` and `DPI_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 49. Use Google Cloud DNS API to automatically issue cert
First you need to authenticate to gcloud.
```
gcloud init
```
**The `dns_gcloud` script uses the active gcloud configuration and credentials.**
There is no logic inside `dns_gcloud` to override the project and other settings.
If needed, create additional [gcloud configurations](https://cloud.google.com/sdk/gcloud/reference/topic/configurations).
You can change the configuration being used without *activating* it; simply set the `CLOUDSDK_ACTIVE_CONFIG_NAME` environment variable.
To issue a certificate you can:
```
export CLOUDSDK_ACTIVE_CONFIG_NAME=default # see the note above
acme.sh --issue --dns dns_gcloud -d example.com -d '*.example.com'
```
`dns_gcloud` also supports [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode).
## 50. Use ConoHa API
First you need to login to your ConoHa account to get your API credentials.
```
export CONOHA_Username="xxxxxx"
export CONOHA_Password="xxxxxx"
export CONOHA_TenantId="xxxxxx"
export CONOHA_IdentityServiceApi="https://identity.xxxx.conoha.io/v2.0"
```
To issue a cert:
```
acme.sh --issue --dns dns_conoha -d example.com -d www.example.com
```
The `CONOHA_Username`, `CONOHA_Password`, `CONOHA_TenantId` and `CONOHA_IdentityServiceApi` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 51. Use netcup DNS API to automatically issue cert
First you need to login in your CCP account to get your API Key and API Password.
```
export NC_Apikey="<Apikey>"
export NC_Apipw="<Apipassword>"
export NC_CID="<Customernumber>"
```
Now, let's issue a cert:
```
acme.sh --issue --dns dns_netcup -d example.com -d www.example.com
```
The `NC_Apikey`,`NC_Apipw` and `NC_CID` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 52. Use GratisDNS.dk
GratisDNS.dk (https://gratisdns.dk/) does not provide an API to update DNS records (other than IPv4 and IPv6
dynamic DNS addresses). The acme.sh plugin therefore retrieves and updates domain TXT records by logging
into the GratisDNS website to read the HTML and posting updates as HTTP. The plugin needs to know your
userid and password for the GratisDNS website.
```sh
export GDNSDK_Username="..."
export GDNSDK_Password="..."
```
The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
Now you can issue a certificate.
Note: It usually takes a few minutes (usually 3-4 minutes) before the changes propagates to gratisdns.dk nameservers (ns3.gratisdns.dk often are slow),
and in rare cases I have seen over 5 minutes before google DNS catches it. Therefor a DNS sleep of at least 300 seconds are recommended-
```sh
acme.sh --issue --dns dns_gdnsdk --dnssleep 300 -d example.com -d *.example.com
```
## 53. Use Namecheap
You will need your namecheap username, API KEY (https://www.namecheap.com/support/api/intro.aspx) and your external IP address (or an URL to get it), this IP will need to be whitelisted at Namecheap.
Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise.
```sh
export NAMECHEAP_USERNAME="..."
export NAMECHEAP_API_KEY="..."
export NAMECHEAP_SOURCEIP="..."
```
NAMECHEAP_SOURCEIP can either be an IP address or an URL to provide it (e.g. https://ifconfig.co/ip).
The username and password will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
Now you can issue a certificate.
```sh
acme.sh --issue --dns dns_namecheap -d example.com -d *.example.com
```
## 54. Use MyDNS.JP API
First, register to MyDNS.JP and get MasterID and Password.
```
export MYDNSJP_MasterID=MasterID
export MYDNSJP_Password=Password
```
To issue a certificate:
```
acme.sh --issue --dns dns_mydnsjp -d example.com -d www.example.com
```
The `MYDNSJP_MasterID` and `MYDNSJP_Password` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 55. Use hosting.de API
Create an API key in your hosting.de account here: https://secure.hosting.de
The key needs the following rights:
- DNS_ZONES_EDIT
- DNS_ZONES_LIST
Set your API Key and endpoint:
```
export HOSTINGDE_APIKEY='xxx'
export HOSTINGDE_ENDPOINT='https://secure.hosting.de'
```
The plugin can also be used for the http.net API. http.net customers have to set endpoint to https://partner.http.net.
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_hostingde -d example.com -d *.example.com
```
The hosting.de API key and endpoint will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 56. Use Neodigit.net API
```
export NEODIGIT_API_TOKEN="eXJxTkdUVUZmcHQ3QWJackQ4ZGlMejRDSklRYmo5VG5zcFFKK2thYnE0WnVnNnMy"
```
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_neodigit -d example.com -d www.example.com
```
Neodigit API Token will be saved in `~/.acme.sh/account.conf` and will be used when needed.
## 57. Use Exoscale API
Create an API key and secret key in the Exoscale account section
Set your API and secret key:
```
export EXOSCALE_API_KEY='xxx'
export EXOSCALE_SECRET_KEY='xxx'
```
Now, let's issue a cert:
```
acme.sh --issue --dns dns_exoscale -d example.com -d www.example.com
```
The `EXOSCALE_API_KEY` and `EXOSCALE_SECRET_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 58. Using PointHQ API to issue certs
Log into [PointHQ account management](https://app.pointhq.com/profile) and copy the API key from the page there.
```export PointHQ_Key="apikeystringgoeshere"
exportPointHQ_Email="accountemail@yourdomain.com"
```
You can then issue certs by using:
```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com
```
## 59. Use Active24 API
Create an API token in the Active24 account section, documentation on https://faq.active24.com/cz/790131-REST-API-rozhran%C3%AD.
Set your API token:
```
export ACTIVE24_Token='xxx'
```
Now, let's issue a cert, set `dnssleep` for propagation new DNS record:
```
acme.sh --issue --dns dns_active24 -d example.com -d www.example.com --dnssleep 1000
```
The `ACTIVE24_Token` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 60. Use do.de API
Create an API token in your do.de account.
Set your API token:
```
export DO_LETOKEN='FmD408PdqT1E269gUK57'
```
To issue a certificate run:
```
acme.sh --issue --dns dns_doapi -d example.com -d *.example.com
```
The API token will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 61. Use Nexcess API
First, you'll need to login to the [Nexcess.net Client Portal](https://portal.nexcess.net) and [generate a new API token](https://portal.nexcess.net/api-token).
Once you have a token, set it in your systems environment:
```
export NW_API_TOKEN="YOUR_TOKEN_HERE"
export NW_API_ENDPOINT="https://portal.nexcess.net"
```
Finally, we'll issue the certificate: (Nexcess DNS publishes at max every 15 minutes, we recommend setting a 900 second `--dnssleep`)
```
acme.sh --issue --dns dns_nw -d example.com --dnssleep 900
```
The `NW_API_TOKEN` and `NW_API_ENDPOINT` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 62. Use Thermo.io API
First, you'll need to login to the [Thermo.io Client Portal](https://core.thermo.io) and [generate a new API token](https://core.thermo.io/api-token).
Once you have a token, set it in your systems environment:
```
export NW_API_TOKEN="YOUR_TOKEN_HERE"
export NW_API_ENDPOINT="https://core.thermo.io"
```
Finally, we'll issue the certificate: (Thermo DNS publishes at max every 15 minutes, we recommend setting a 900 second `--dnssleep`)
```
acme.sh --issue --dns dns_nw -d example.com --dnssleep 900
```
The `NW_API_TOKEN` and `NW_API_ENDPOINT` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 63. Use Futurehosting API
First, you'll need to login to the [Futurehosting Client Portal](https://my.futurehosting.com) and [generate a new API token](https://my.futurehosting.com/api-token).
Once you have a token, set it in your systems environment:
```
export NW_API_TOKEN="YOUR_TOKEN_HERE"
export NW_API_ENDPOINT="https://my.futurehosting.com"
```
Finally, we'll issue the certificate: (Futurehosting DNS publishes at max every 15 minutes, we recommend setting a 900 second `--dnssleep`)
```
acme.sh --issue --dns dns_nw -d example.com --dnssleep 900
```
The `NW_API_TOKEN` and `NW_API_ENDPOINT` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 64. Use Rackspace API
Set username and API key, which is available under "My Profile & Settings"
```
export RACKSPACE_Username='username'
export RACKSPACE_Apikey='xxx'
```
Now, let's issue a cert:
```
acme.sh --issue --dns dns_rackspace -d example.com -d www.example.com
```
## 65. Use Online API
First, you'll need to retrive your API key, which is available under https://console.online.net/en/api/access
```
export ONLINE_API_KEY='xxx'
```
To issue a cert run:
```
acme.sh --issue --dns dns_online -d example.com -d www.example.com
```
`ONLINE_API_KEY` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
## 66. Use MyDevil.net
Make sure that you can execute own binaries:
```sh
devil binexec on
```
Install acme.sh, or simply `git clone` it into some directory on your MyDevil host account (in which case you should link to it from your `~/bin` directory).
If you're not using private IP and depend on default IP provided by host, you may want to edit `crontab` too, and make sure that `acme.sh --cron` is run also after reboot (you can find out how to do that on their wiki pages).
To issue a new certificate, run:
```sh
acme.sh --issue --dns dns_mydevil -d example.com -d *.example.com
```
After certificate is ready, you can install it with [deploy command](../deploy/README.md#14-deploy-your-cert-on-mydevilnet).
# Use custom API
......
#!/usr/bin/env sh
#
#Author: Wolfgang Ebner
#Report Bugs here: https://github.com/webner/acme.sh
#
######## Public functions #####################
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_acmedns_add() {
fulldomain=$1
txtvalue=$2
_info "Using acme-dns"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}"
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}"
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}"
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}"
if [ "$ACMEDNS_UPDATE_URL" = "" ]; then
ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update"
fi
_saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL"
_saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME"
_saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD"
_saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN"
export _H1="X-Api-User: $ACMEDNS_USERNAME"
export _H2="X-Api-Key: $ACMEDNS_PASSWORD"
data="{\"subdomain\":\"$ACMEDNS_SUBDOMAIN\", \"txt\": \"$txtvalue\"}"
_debug data "$data"
response="$(_post "$data" "$ACMEDNS_UPDATE_URL" "" "POST")"
_debug response "$response"
if ! echo "$response" | grep "\"$txtvalue\"" >/dev/null; then
_err "invalid response of acme-dns"
return 1
fi
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_acmedns_rm() {
fulldomain=$1
txtvalue=$2
_info "Using acme-dns"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
}
#################### Private functions below ##################################
#!/usr/bin/env sh
#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
ACTIVE24_Api="https://api.active24.com"
######## Public functions #####################
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_active24_add() {
fulldomain=$1
txtvalue=$2
_active24_init
_info "Adding txt record"
if _active24_rest POST "dns/$_domain/txt/v1" "{\"name\":\"$_sub_domain\",\"text\":\"$txtvalue\",\"ttl\":0}"; then
if _contains "$response" "errors"; then
_err "Add txt record error."
return 1
else
_info "Added, OK"
return 0
fi
fi
_err "Add txt record error."
return 1
}
# Usage: fulldomain txtvalue
# Used to remove the txt record after validation
dns_active24_rm() {
fulldomain=$1
txtvalue=$2
_active24_init
_debug "Getting txt records"
_active24_rest GET "dns/$_domain/records/v1"
if _contains "$response" "errors"; then
_err "Error"
return 1
fi
hash_ids=$(echo "$response" | _egrep_o "[^{]+${txtvalue}[^}]+" | _egrep_o "hashId\":\"[^\"]+" | cut -c10-)
for hash_id in $hash_ids; do
_debug "Removing hash_id" "$hash_id"
if _active24_rest DELETE "dns/$_domain/$hash_id/v1" ""; then
if _contains "$response" "errors"; then
_err "Unable to remove txt record."
return 1
else
_info "Removed txt record."
return 0
fi
fi
done
_err "No txt records found."
return 1
}
#################### Private functions below ##################################
#_acme-challenge.www.domain.com
#returns
# _sub_domain=_acme-challenge.www
# _domain=domain.com
# _domain_id=sdjkglgdfewsdfg
_get_root() {
domain=$1
if ! _active24_rest GET "dns/domains/v1"; then
return 1
fi
i=2
p=1
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug "h" "$h"
if [ -z "$h" ]; then
#not valid
return 1
fi
if _contains "$response" "\"$h\"" >/dev/null; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
return 0
fi
p=$i
i=$(_math "$i" + 1)
done
return 1
}
_active24_rest() {
m=$1
ep="$2"
data="$3"
_debug "$ep"
export _H1="Authorization: Bearer $ACTIVE24_Token"
if [ "$m" != "GET" ]; then
_debug "data" "$data"
response="$(_post "$data" "$ACTIVE24_Api/$ep" "" "$m" "application/json")"
else
response="$(_get "$ACTIVE24_Api/$ep")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}
_active24_init() {
ACTIVE24_Token="${ACTIVE24_Token:-$(_readaccountconf_mutable ACTIVE24_Token)}"
if [ -z "$ACTIVE24_Token" ]; then
ACTIVE24_Token=""
_err "You didn't specify a Active24 api token yet."
_err "Please create the token and try again."
return 1
fi
_saveaccountconf_mutable ACTIVE24_Token "ACTIVE24_Token"
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
fi
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
}
......@@ -29,7 +29,7 @@ dns_aws_add() {
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
AWS_ACCESS_KEY_ID=""
AWS_SECRET_ACCESS_KEY=""
_err "You don't specify aws route53 api key id and and api key secret yet."
_err "You haven't specifed the aws route53 api key id and and api key secret yet."
_err "Please create your key and try again. see $(__green $AWS_WIKI)"
return 1
fi
......@@ -62,7 +62,7 @@ dns_aws_add() {
fi
if [ "$_resource_record" ] && _contains "$response" "$txtvalue"; then
_info "The txt record already exists, skip"
_info "The TXT record already exists. Skipping."
return 0
fi
......@@ -71,7 +71,7 @@ dns_aws_add() {
_aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>UPSERT</Action><ResourceRecordSet><Name>$fulldomain</Name><Type>TXT</Type><TTL>300</TTL><ResourceRecords>$_resource_record<ResourceRecord><Value>\"$txtvalue\"</Value></ResourceRecord></ResourceRecords></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
_info "txt record updated success."
_info "TXT record updated successfully."
return 0
fi
......@@ -99,7 +99,7 @@ dns_aws_rm() {
_debug _sub_domain "$_sub_domain"
_debug _domain "$_domain"
_info "Geting existing records for $fulldomain"
_info "Getting existing records for $fulldomain"
if ! aws_rest GET "2013-04-01$_domain_id/rrset" "name=$fulldomain&type=TXT"; then
return 1
fi
......@@ -108,14 +108,14 @@ dns_aws_rm() {
_resource_record="$(echo "$response" | sed 's/<ResourceRecordSet>/"/g' | tr '"' "\n" | grep "<Name>$fulldomain.</Name>" | _egrep_o "<ResourceRecords.*</ResourceRecords>" | sed "s/<ResourceRecords>//" | sed "s#</ResourceRecords>##")"
_debug "_resource_record" "$_resource_record"
else
_debug "no records exists, skip"
_debug "no records exist, skip"
return 0
fi
_aws_tmpl_xml="<ChangeResourceRecordSetsRequest xmlns=\"https://route53.amazonaws.com/doc/2013-04-01/\"><ChangeBatch><Changes><Change><Action>DELETE</Action><ResourceRecordSet><ResourceRecords>$_resource_record</ResourceRecords><Name>$fulldomain.</Name><Type>TXT</Type><TTL>300</TTL></ResourceRecordSet></Change></Changes></ChangeBatch></ChangeResourceRecordSetsRequest>"
if aws_rest POST "2013-04-01$_domain_id/rrset/" "" "$_aws_tmpl_xml" && _contains "$response" "ChangeResourceRecordSetsResponse"; then
_info "txt record deleted success."
_info "TXT record deleted successfully."
return 0
fi
......@@ -163,7 +163,7 @@ _get_root() {
_domain=$h
return 0
fi
_err "Can not find domain id: $h"
_err "Can't find domain with id: $h"
return 1
fi
fi
......
......@@ -76,10 +76,10 @@ dns_azure_add() {
values="{\"value\":[\"$txtvalue\"]}"
timestamp="$(_time)"
if [ "$_code" = "200" ]; then
vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"")"
vlist="$(echo "$response" | _egrep_o "\"value\"\\s*:\\s*\\[\\s*\"[^\"]*\"\\s*]" | cut -d : -f 2 | tr -d "[]\"")"
_debug "existing TXT found"
_debug "$vlist"
existingts="$(echo "$response" | _egrep_o "\"acmetscheck\"\s*:\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")"
existingts="$(echo "$response" | _egrep_o "\"acmetscheck\"\\s*:\\s*\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d "\"")"
if [ -z "$existingts" ]; then
# the record was not created by acme.sh. Copy the exisiting entires
existingts=$timestamp
......@@ -172,7 +172,7 @@ dns_azure_rm() {
_azure_rest GET "$acmeRecordURI" "" "$accesstoken"
timestamp="$(_time)"
if [ "$_code" = "200" ]; then
vlist="$(echo "$response" | _egrep_o "\"value\"\s*:\s*\[\s*\"[^\"]*\"\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")"
vlist="$(echo "$response" | _egrep_o "\"value\"\\s*:\\s*\\[\\s*\"[^\"]*\"\\s*]" | cut -d : -f 2 | tr -d "[]\"" | grep -v "$txtvalue")"
values=""
comma=""
for v in $vlist; do
......@@ -230,7 +230,7 @@ _azure_rest() {
fi
_ret="$?"
_secure_debug2 "response $response"
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
_debug "http response code $_code"
if [ "$_code" = "401" ]; then
# we have an invalid access token set to expired
......@@ -308,7 +308,7 @@ _get_root() {
domain=$1
subscriptionId=$2
accesstoken=$3
i=2
i=1
p=1
## Ref: https://docs.microsoft.com/en-us/rest/api/dns/zones/list
......@@ -316,7 +316,7 @@ _get_root() {
## (ZoneListResult with continuation token for the next page of results)
## Per https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#dns-limits you are limited to 100 Zone/subscriptions anyways
##
_azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?api-version=2017-09-01" "" "$accesstoken"
_azure_rest GET "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Network/dnszones?\$top=500&api-version=2017-09-01" "" "$accesstoken"
# Find matching domain name is Json response
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
......@@ -328,9 +328,14 @@ _get_root() {
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(echo "$response" | _egrep_o "\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \")
_domain_id=$(echo "$response" | _egrep_o "\\{\"id\":\"[^\"]*$h\"" | head -n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
if [ "$i" = 1 ]; then
#create the record at the domain apex (@) if only the domain name was provided as --domain-alias
_sub_domain="@"
else
_sub_domain=$(echo "$domain" | cut -d . -f 1-$p)
fi
_domain=$h
return 0
fi
......
......@@ -19,8 +19,8 @@ dns_cf_add() {
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key=""
CF_Email=""
_err "You didn't specify a cloudflare api key and email yet."
_err "Please create the key and try again."
_err "You didn't specify a Cloudflare api key and email yet."
_err "You can get yours from here https://dash.cloudflare.com/profile."
return 1
fi
......@@ -58,9 +58,12 @@ dns_cf_add() {
# if [ "$count" = "0" ]; then
_info "Adding record"
if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then
if _contains "$response" "$fulldomain"; then
_info "Added, OK"
return 0
elif _contains "$response" "The record already exists"; then
_info "Already exists, OK"
return 0
else
_err "Add txt record error."
return 1
......@@ -94,8 +97,8 @@ dns_cf_rm() {
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
CF_Key=""
CF_Email=""
_err "You didn't specify a cloudflare api key and email yet."
_err "Please create the key and try again."
_err "You didn't specify a Cloudflare api key and email yet."
_err "You can get yours from here https://dash.cloudflare.com/profile."
return 1
fi
......@@ -159,7 +162,7 @@ _get_root() {
fi
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
_domain_id=$(printf "%s\n" "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | head -n 1 | cut -d : -f 2 | tr -d \")
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
if [ "$_domain_id" ]; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment