mirror of
https://github.com/plantroon/acme.sh.git
synced 2024-12-22 21:21:42 +00:00
commit
909aba27d1
46
README.md
46
README.md
@ -70,11 +70,16 @@ For all build statuses, check our [weekly build project](https://github.com/Neil
|
|||||||
|
|
||||||
https://github.com/Neilpang/acmetest
|
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
|
# Supported modes
|
||||||
|
|
||||||
- Webroot mode
|
- Webroot mode
|
||||||
- Standalone mode
|
- Standalone mode
|
||||||
|
- Standalone tls-alpn mode
|
||||||
- Apache mode
|
- Apache mode
|
||||||
- Nginx mode
|
- Nginx mode
|
||||||
- DNS 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
|
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
||||||
|
|
||||||
|
# 5. Use Standalone ssl server to issue cert
|
||||||
|
|
||||||
# 5. Use Apache mode
|
**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))**
|
||||||
|
|
||||||
|
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)**
|
**(requires you to be root/sudoer, since it is required to interact with Apache server)**
|
||||||
|
|
||||||
@ -242,7 +259,7 @@ 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
|
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)**
|
**(requires you to be root/sudoer, since it is required to interact with Nginx server)**
|
||||||
|
|
||||||
@ -266,7 +283,7 @@ 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
|
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.
|
If your DNS provider supports API access, we can use that API to automatically issue the certs.
|
||||||
|
|
||||||
@ -330,6 +347,7 @@ You don't have to do anything manually!
|
|||||||
1. MyDNS.JP API (https://www.mydns.jp/)
|
1. MyDNS.JP API (https://www.mydns.jp/)
|
||||||
1. hosting.de (https://www.hosting.de)
|
1. hosting.de (https://www.hosting.de)
|
||||||
1. Neodigit.net API (https://www.neodigit.net)
|
1. Neodigit.net API (https://www.neodigit.net)
|
||||||
|
1. Exoscale.com API (https://www.exoscale.com/)
|
||||||
|
|
||||||
And:
|
And:
|
||||||
|
|
||||||
@ -343,7 +361,7 @@ 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)
|
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.
|
See: https://github.com/Neilpang/acme.sh/wiki/dns-manual-mode first.
|
||||||
|
|
||||||
@ -379,7 +397,7 @@ Ok, it's done.
|
|||||||
|
|
||||||
**Please use dns api mode instead.**
|
**Please use dns api mode instead.**
|
||||||
|
|
||||||
# 9. Issue ECC certificates
|
# 10. Issue ECC certificates
|
||||||
|
|
||||||
`Let's Encrypt` can now issue **ECDSA** certificates.
|
`Let's Encrypt` can now issue **ECDSA** certificates.
|
||||||
|
|
||||||
@ -411,7 +429,7 @@ Valid values are:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 10. Issue Wildcard certificates
|
# 11. Issue Wildcard certificates
|
||||||
|
|
||||||
It's simple, just give a wildcard domain as the `-d` parameter.
|
It's simple, just give a wildcard domain as the `-d` parameter.
|
||||||
|
|
||||||
@ -421,7 +439,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.
|
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
|
||||||
|
|
||||||
@ -438,7 +456,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:
|
To stop renewal of a cert, you can execute the following to remove the cert from the renewal list:
|
||||||
|
|
||||||
@ -451,7 +469,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.
|
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.
|
acme.sh is in constant development, so it's strongly recommended to use the latest code.
|
||||||
|
|
||||||
@ -476,25 +494,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
|
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".
|
Speak ACME language using shell, directly to "Let's Encrypt".
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
|
|
||||||
|
|
||||||
# 16. Acknowledgments
|
# 17. Acknowledgments
|
||||||
|
|
||||||
1. Acme-tiny: https://github.com/diafygi/acme-tiny
|
1. Acme-tiny: https://github.com/diafygi/acme-tiny
|
||||||
2. ACME protocol: https://github.com/ietf-wg-acme/acme
|
2. ACME protocol: https://github.com/ietf-wg-acme/acme
|
||||||
|
|
||||||
|
|
||||||
# 17. License & Others
|
# 18. License & Others
|
||||||
|
|
||||||
License is GPLv3
|
License is GPLv3
|
||||||
|
|
||||||
@ -503,7 +521,7 @@ 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.
|
[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:
|
Your donation makes **acme.sh** better:
|
||||||
|
|
||||||
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
|
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
|
||||||
|
93
acme.sh
93
acme.sh
@ -36,11 +36,11 @@ _OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org"
|
|||||||
VTYPE_HTTP="http-01"
|
VTYPE_HTTP="http-01"
|
||||||
VTYPE_DNS="dns-01"
|
VTYPE_DNS="dns-01"
|
||||||
VTYPE_TLS="tls-sni-01"
|
VTYPE_TLS="tls-sni-01"
|
||||||
VTYPE_TLS2="tls-sni-02"
|
VTYPE_ALPN="tls-alpn-01"
|
||||||
|
|
||||||
LOCAL_ANY_ADDRESS="0.0.0.0"
|
LOCAL_ANY_ADDRESS="0.0.0.0"
|
||||||
|
|
||||||
MAX_RENEW=60
|
DEFAULT_RENEW=60
|
||||||
|
|
||||||
DEFAULT_DNS_SLEEP=120
|
DEFAULT_DNS_SLEEP=120
|
||||||
|
|
||||||
@ -48,6 +48,7 @@ NO_VALUE="no"
|
|||||||
|
|
||||||
W_TLS="tls"
|
W_TLS="tls"
|
||||||
W_DNS="dns"
|
W_DNS="dns"
|
||||||
|
W_ALPN="alpn"
|
||||||
DNS_ALIAS_PREFIX="="
|
DNS_ALIAS_PREFIX="="
|
||||||
|
|
||||||
MODE_STATELESS="stateless"
|
MODE_STATELESS="stateless"
|
||||||
@ -1046,7 +1047,7 @@ _idn() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
#_createcsr cn san_list keyfile csrfile conf
|
#_createcsr cn san_list keyfile csrfile conf acmeValidationv1
|
||||||
_createcsr() {
|
_createcsr() {
|
||||||
_debug _createcsr
|
_debug _createcsr
|
||||||
domain="$1"
|
domain="$1"
|
||||||
@ -1054,6 +1055,7 @@ _createcsr() {
|
|||||||
csrkey="$3"
|
csrkey="$3"
|
||||||
csr="$4"
|
csr="$4"
|
||||||
csrconf="$5"
|
csrconf="$5"
|
||||||
|
acmeValidationv1="$6"
|
||||||
_debug2 domain "$domain"
|
_debug2 domain "$domain"
|
||||||
_debug2 domainlist "$domainlist"
|
_debug2 domainlist "$domainlist"
|
||||||
_debug2 csrkey "$csrkey"
|
_debug2 csrkey "$csrkey"
|
||||||
@ -1062,7 +1064,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"
|
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
|
#single domain
|
||||||
_info "Single domain" "$domain"
|
_info "Single domain" "$domain"
|
||||||
printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
|
printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
|
||||||
@ -1084,6 +1088,10 @@ _createcsr() {
|
|||||||
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
|
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$acmeValidationv1" ]; then
|
||||||
|
printf "\n1.3.6.1.5.5.7.1.30.1=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}"
|
||||||
|
fi
|
||||||
|
|
||||||
_csr_cn="$(_idn "$domain")"
|
_csr_cn="$(_idn "$domain")"
|
||||||
_debug2 _csr_cn "$_csr_cn"
|
_debug2 _csr_cn "$_csr_cn"
|
||||||
if _contains "$(uname -a)" "MINGW"; then
|
if _contains "$(uname -a)" "MINGW"; then
|
||||||
@ -1134,12 +1142,17 @@ _readSubjectAltNamesFromCSR() {
|
|||||||
|
|
||||||
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
|
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
|
||||||
_debug "AltNames contains subject"
|
_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
|
else
|
||||||
_debug "AltNames doesn't contain subject"
|
_debug "AltNames doesn't contain subject"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
|
echo "$_dnsAltnames" | sed "s/DNS://g"
|
||||||
}
|
}
|
||||||
|
|
||||||
#_csrfile
|
#_csrfile
|
||||||
@ -1516,7 +1529,8 @@ _calcjwk() {
|
|||||||
JWK_HEADERPLACE_PART1='{"nonce": "'
|
JWK_HEADERPLACE_PART1='{"nonce": "'
|
||||||
JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
|
JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
|
||||||
else
|
else
|
||||||
_err "Only RSA or EC key is supported."
|
_err "Only RSA or EC key is supported. keyfile=$keyfile"
|
||||||
|
_debug2 "$(cat "$keyfile")"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -1860,11 +1874,7 @@ _send_signed_request() {
|
|||||||
sig="$(printf "%s" "$_sig_t" | _url_replace)"
|
sig="$(printf "%s" "$_sig_t" | _url_replace)"
|
||||||
_debug3 sig "$sig"
|
_debug3 sig "$sig"
|
||||||
|
|
||||||
if [ "$ACME_VERSION" = "2" ]; then
|
|
||||||
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
|
body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
|
||||||
else
|
|
||||||
body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
|
|
||||||
fi
|
|
||||||
_debug3 body "$body"
|
_debug3 body "$body"
|
||||||
|
|
||||||
response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
|
response="$(_post "$body" "$url" "$needbase64" "POST" "$__request_conent_type")"
|
||||||
@ -2101,7 +2111,7 @@ _sleep() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# _starttlsserver san_a san_b port content _ncaddr
|
# _starttlsserver san_a san_b port content _ncaddr acmeValidationv1
|
||||||
_starttlsserver() {
|
_starttlsserver() {
|
||||||
_info "Starting tls server."
|
_info "Starting tls server."
|
||||||
san_a="$1"
|
san_a="$1"
|
||||||
@ -2109,10 +2119,12 @@ _starttlsserver() {
|
|||||||
port="$3"
|
port="$3"
|
||||||
content="$4"
|
content="$4"
|
||||||
opaddr="$5"
|
opaddr="$5"
|
||||||
|
acmeValidationv1="$6"
|
||||||
|
|
||||||
_debug san_a "$san_a"
|
_debug san_a "$san_a"
|
||||||
_debug san_b "$san_b"
|
_debug san_b "$san_b"
|
||||||
_debug port "$port"
|
_debug port "$port"
|
||||||
|
_debug acmeValidationv1 "$acmeValidationv1"
|
||||||
|
|
||||||
#create key TLS_KEY
|
#create key TLS_KEY
|
||||||
if ! _createkey "2048" "$TLS_KEY"; then
|
if ! _createkey "2048" "$TLS_KEY"; then
|
||||||
@ -2125,7 +2137,7 @@ _starttlsserver() {
|
|||||||
if [ "$san_b" ]; then
|
if [ "$san_b" ]; then
|
||||||
alt="$alt,$san_b"
|
alt="$alt,$san_b"
|
||||||
fi
|
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."
|
_err "Create tls validation csr error."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@ -2151,6 +2163,10 @@ _starttlsserver() {
|
|||||||
__S_OPENSSL="$__S_OPENSSL -6"
|
__S_OPENSSL="$__S_OPENSSL -6"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$acmeValidationv1" ]; then
|
||||||
|
__S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1"
|
||||||
|
fi
|
||||||
|
|
||||||
_debug "$__S_OPENSSL"
|
_debug "$__S_OPENSSL"
|
||||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
||||||
$__S_OPENSSL -tlsextdebug &
|
$__S_OPENSSL -tlsextdebug &
|
||||||
@ -3061,8 +3077,8 @@ _on_before_issue() {
|
|||||||
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
|
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
|
||||||
fi
|
fi
|
||||||
_checkport="$Le_HTTPPort"
|
_checkport="$Le_HTTPPort"
|
||||||
elif [ "$_currentRoot" = "$W_TLS" ]; then
|
elif [ "$_currentRoot" = "$W_TLS" ] || [ "$_currentRoot" = "$W_ALPN" ]; then
|
||||||
_info "Standalone tls mode."
|
_info "Standalone tls/alpn mode."
|
||||||
if [ -z "$Le_TLSPort" ]; then
|
if [ -z "$Le_TLSPort" ]; then
|
||||||
Le_TLSPort=443
|
Le_TLSPort=443
|
||||||
else
|
else
|
||||||
@ -3422,15 +3438,17 @@ __get_domain_new_authz() {
|
|||||||
|
|
||||||
#uri keyAuthorization
|
#uri keyAuthorization
|
||||||
__trigger_validation() {
|
__trigger_validation() {
|
||||||
_debug2 "tigger domain validation."
|
_debug2 "Trigger domain validation."
|
||||||
_t_url="$1"
|
_t_url="$1"
|
||||||
_debug2 _t_url "$_t_url"
|
_debug2 _t_url "$_t_url"
|
||||||
_t_key_authz="$2"
|
_t_key_authz="$2"
|
||||||
_debug2 _t_key_authz "$_t_key_authz"
|
_debug2 _t_key_authz "$_t_key_authz"
|
||||||
|
_t_vtype="$3"
|
||||||
|
_debug2 _t_vtype "$_t_vtype"
|
||||||
if [ "$ACME_VERSION" = "2" ]; then
|
if [ "$ACME_VERSION" = "2" ]; then
|
||||||
_send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}"
|
_send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}"
|
||||||
else
|
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
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3681,11 +3699,11 @@ $_authorizations_map"
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$_currentRoot" = "$W_TLS" ]; then
|
if [ "$_currentRoot" = "$W_TLS" ]; then
|
||||||
if [ "$ACME_VERSION" = "2" ]; then
|
|
||||||
vtype="$VTYPE_TLS2"
|
|
||||||
else
|
|
||||||
vtype="$VTYPE_TLS"
|
vtype="$VTYPE_TLS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$_currentRoot" = "$W_ALPN" ]; then
|
||||||
|
vtype="$VTYPE_ALPN"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$ACME_VERSION" = "2" ]; then
|
if [ "$ACME_VERSION" = "2" ]; then
|
||||||
@ -4001,9 +4019,19 @@ $_authorizations_map"
|
|||||||
_on_issue_err "$_post_hook" "$vlist"
|
_on_issue_err "$_post_hook" "$vlist"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
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
|
||||||
|
_on_issue_err "$_post_hook" "$vlist"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! __trigger_validation "$uri" "$keyauthorization"; then
|
if ! __trigger_validation "$uri" "$keyauthorization" "$vtype"; then
|
||||||
_err "$d:Can not get challenge: $response"
|
_err "$d:Can not get challenge: $response"
|
||||||
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
||||||
_clearup
|
_clearup
|
||||||
@ -4012,7 +4040,7 @@ $_authorizations_map"
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$code" ] && [ "$code" != '202' ]; then
|
if [ "$code" ] && [ "$code" != '202' ]; then
|
||||||
if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then
|
if [ "$code" = '200' ]; then
|
||||||
_debug "trigger validation code: $code"
|
_debug "trigger validation code: $code"
|
||||||
else
|
else
|
||||||
_err "$d:Challenge error: $response"
|
_err "$d:Challenge error: $response"
|
||||||
@ -4239,8 +4267,8 @@ $_authorizations_map"
|
|||||||
Le_CertCreateTimeStr=$(date -u)
|
Le_CertCreateTimeStr=$(date -u)
|
||||||
_savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
|
_savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
|
||||||
|
|
||||||
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then
|
if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ]; then
|
||||||
Le_RenewalDays="$MAX_RENEW"
|
Le_RenewalDays="$DEFAULT_RENEW"
|
||||||
else
|
else
|
||||||
_savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
|
_savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
|
||||||
fi
|
fi
|
||||||
@ -5463,6 +5491,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.
|
--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.
|
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
|
||||||
--standalone Use standalone mode.
|
--standalone Use standalone mode.
|
||||||
|
--alpn Use standalone alpn mode.
|
||||||
--stateless Use stateless mode, see: $_STATELESS_WIKI
|
--stateless Use stateless mode, see: $_STATELESS_WIKI
|
||||||
--apache Use apache mode.
|
--apache Use apache mode.
|
||||||
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
|
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
|
||||||
@ -5491,8 +5520,9 @@ Parameters:
|
|||||||
--useragent Specifies the user agent string. it will be saved for future use too.
|
--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.
|
--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.
|
--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.
|
--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.
|
--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.
|
--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.
|
--stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
|
||||||
@ -5817,6 +5847,14 @@ _process() {
|
|||||||
_webroot="$_webroot,$wvalue"
|
_webroot="$_webroot,$wvalue"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
--alpn)
|
||||||
|
wvalue="$W_ALPN"
|
||||||
|
if [ -z "$_webroot" ]; then
|
||||||
|
_webroot="$wvalue"
|
||||||
|
else
|
||||||
|
_webroot="$_webroot,$wvalue"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
--stateless)
|
--stateless)
|
||||||
wvalue="$MODE_STATELESS"
|
wvalue="$MODE_STATELESS"
|
||||||
if [ -z "$_webroot" ]; then
|
if [ -z "$_webroot" ]; then
|
||||||
@ -5941,6 +5979,11 @@ _process() {
|
|||||||
Le_HTTPPort="$_httpport"
|
Le_HTTPPort="$_httpport"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
--tlsport)
|
||||||
|
_tlsport="$2"
|
||||||
|
Le_TLSPort="$_tlsport"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
--listraw)
|
--listraw)
|
||||||
_listraw="raw"
|
_listraw="raw"
|
||||||
;;
|
;;
|
||||||
|
@ -146,13 +146,17 @@ Finally, make the DNS server and update Key available to `acme.sh`
|
|||||||
export NSUPDATE_SERVER="dns.example.com"
|
export NSUPDATE_SERVER="dns.example.com"
|
||||||
export NSUPDATE_KEY="/path/to/your/nsupdate.key"
|
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:
|
Ok, let's issue a cert now:
|
||||||
```
|
```
|
||||||
acme.sh --issue --dns dns_nsupdate -d example.com -d www.example.com
|
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
|
## 8. Use LuaDNS domain API
|
||||||
@ -263,25 +267,26 @@ when needed.
|
|||||||
|
|
||||||
## 14. Use Linode domain API
|
## 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.
|
First you need to login to your Linode account to get your API Key.
|
||||||
|
|
||||||
* [Classic Manager](https://manager.linode.com/profile/api)
|
Then add an API key with label *ACME* and copy the new key into the following
|
||||||
|
command.
|
||||||
Under "Add an API key", Give the new key a "Label" (we recommend *ACME*),
|
|
||||||
set the expiry to never, "Create API Key", and copy the new key into the `LINODE_API_KEY` command
|
|
||||||
below.
|
|
||||||
|
|
||||||
* [Cloud Manager](https://cloud.linode.com/profile/tokens)
|
|
||||||
|
|
||||||
Click on "Add a Personal Access Token". Give the new key a "Label" (we
|
|
||||||
recommend *ACME*), give it Read/Write access to "Domains". "Submit", and
|
|
||||||
copy the new key into the `LINODE_API_KEY` command below.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export LINODE_API_KEY="..."
|
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:
|
Ok, let's issue a cert now:
|
||||||
|
|
||||||
@ -289,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
|
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
|
## 15. Use FreeDNS
|
||||||
|
|
||||||
@ -1076,6 +1109,24 @@ 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.
|
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_netcup -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.
|
||||||
|
|
||||||
# Use custom API
|
# Use custom API
|
||||||
|
|
||||||
If your API is not supported yet, you can write your own DNS API.
|
If your API is not supported yet, you can write your own DNS API.
|
||||||
|
@ -34,9 +34,6 @@ dns_cf_add() {
|
|||||||
_saveaccountconf_mutable CF_Key "$CF_Key"
|
_saveaccountconf_mutable CF_Key "$CF_Key"
|
||||||
_saveaccountconf_mutable CF_Email "$CF_Email"
|
_saveaccountconf_mutable CF_Email "$CF_Email"
|
||||||
|
|
||||||
_DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')"
|
|
||||||
_cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_"
|
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
_err "invalid domain"
|
_err "invalid domain"
|
||||||
@ -105,16 +102,11 @@ dns_cf_rm() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_DOMAIN_CF_ZONES_CACHE_NAME_="$(echo "${CF_Email}_CF_ZONES_" | tr '@.' '__')"
|
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
_cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_"
|
|
||||||
_err "invalid domain"
|
_err "invalid domain"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_cleardomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_"
|
|
||||||
|
|
||||||
_debug _domain_id "$_domain_id"
|
_debug _domain_id "$_domain_id"
|
||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
@ -154,21 +146,6 @@ dns_cf_rm() {
|
|||||||
# _domain=domain.com
|
# _domain=domain.com
|
||||||
# _domain_id=sdjkglgdfewsdfg
|
# _domain_id=sdjkglgdfewsdfg
|
||||||
_get_root() {
|
_get_root() {
|
||||||
|
|
||||||
_cf_zones="$(_readdomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_")"
|
|
||||||
_debug2 "_cf_zones" "$_cf_zones"
|
|
||||||
if [ -z "$_cf_zones" ]; then
|
|
||||||
_debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ is none, so get it."
|
|
||||||
if ! _cf_rest GET "zones"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_cf_zones="$response"
|
|
||||||
_savedomainconf "$_DOMAIN_CF_ZONES_CACHE_NAME_" "$(echo "$_cf_zones" | _base64)"
|
|
||||||
else
|
|
||||||
_debug "$_DOMAIN_CF_ZONES_CACHE_NAME_ found"
|
|
||||||
_cf_zones="$(echo "$_cf_zones" | _dbase64)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
domain=$1
|
domain=$1
|
||||||
i=2
|
i=2
|
||||||
p=1
|
p=1
|
||||||
@ -180,8 +157,12 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if _contains "$_cf_zones" "\"name\":\"$h\"" >/dev/null; then
|
if ! _cf_rest GET "zones?name=$h"; then
|
||||||
_domain_id=$(echo "$_cf_zones" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "^\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "\"name\":\"$h\"" >/dev/null; then
|
||||||
|
_domain_id=$(echo "$response" | _egrep_o "\[.\"id\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
if [ "$_domain_id" ]; then
|
if [ "$_domain_id" ]; then
|
||||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
_domain=$h
|
_domain=$h
|
||||||
|
168
dnsapi/dns_exoscale.sh
Executable file
168
dnsapi/dns_exoscale.sh
Executable file
@ -0,0 +1,168 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
EXOSCALE_API=https://api.exoscale.com/dns/v1
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
# Used to add txt record
|
||||||
|
dns_exoscale_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! _checkAuth; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_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"
|
||||||
|
|
||||||
|
_info "Adding record"
|
||||||
|
if _exoscale_rest POST "domains/$_domain_id/records" "{\"record\":{\"name\":\"$_sub_domain\",\"record_type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":120}}" "$_domain_token"; then
|
||||||
|
if _contains "$response" "$txtvalue"; then
|
||||||
|
_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_exoscale_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! _checkAuth; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_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"
|
||||||
|
|
||||||
|
_debug "Getting txt records"
|
||||||
|
_exoscale_rest GET "domains/${_domain_id}/records?type=TXT&name=$_sub_domain" "" "$_domain_token"
|
||||||
|
if _contains "$response" "\"name\":\"$_sub_domain\"" >/dev/null; then
|
||||||
|
_record_id=$(echo "$response" | tr '{' "\n" | grep "\"content\":\"$txtvalue\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$_record_id" ]; then
|
||||||
|
_err "Can not get record id to remove."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "Deleting record $_record_id"
|
||||||
|
|
||||||
|
if ! _exoscale_rest DELETE "domains/$_domain_id/records/$_record_id" "" "$_domain_token"; then
|
||||||
|
_err "Delete record error."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
|
_checkAuth() {
|
||||||
|
EXOSCALE_API_KEY="${EXOSCALE_API_KEY:-$(_readaccountconf_mutable EXOSCALE_API_KEY)}"
|
||||||
|
EXOSCALE_SECRET_KEY="${EXOSCALE_SECRET_KEY:-$(_readaccountconf_mutable EXOSCALE_SECRET_KEY)}"
|
||||||
|
|
||||||
|
if [ -z "$EXOSCALE_API_KEY" ] || [ -z "$EXOSCALE_SECRET_KEY" ]; then
|
||||||
|
EXOSCALE_API_KEY=""
|
||||||
|
EXOSCALE_SECRET_KEY=""
|
||||||
|
_err "You don't specify Exoscale application key and application secret yet."
|
||||||
|
_err "Please create you key and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable EXOSCALE_API_KEY "$EXOSCALE_API_KEY"
|
||||||
|
_saveaccountconf_mutable EXOSCALE_SECRET_KEY "$EXOSCALE_SECRET_KEY"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#_acme-challenge.www.domain.com
|
||||||
|
#returns
|
||||||
|
# _sub_domain=_acme-challenge.www
|
||||||
|
# _domain=domain.com
|
||||||
|
# _domain_id=sdjkglgdfewsdfg
|
||||||
|
# _domain_token=sdjkglgdfewsdfg
|
||||||
|
_get_root() {
|
||||||
|
|
||||||
|
if ! _exoscale_rest GET "domains"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
domain=$1
|
||||||
|
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" "\"name\":\"$h\"" >/dev/null; then
|
||||||
|
_domain_id=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"id\":[^,]+" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
|
_domain_token=$(echo "$response" | tr '{' "\n" | grep "\"name\":\"$h\"" | _egrep_o "\"token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
|
if [ "$_domain_token" ] && [ "$_domain_id" ]; then
|
||||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
|
_domain=$h
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# returns response
|
||||||
|
_exoscale_rest() {
|
||||||
|
method=$1
|
||||||
|
path="$2"
|
||||||
|
data="$3"
|
||||||
|
token="$4"
|
||||||
|
request_url="$EXOSCALE_API/$path"
|
||||||
|
_debug "$path"
|
||||||
|
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
|
||||||
|
if [ "$token" ]; then
|
||||||
|
export _H2="X-DNS-Domain-Token: $token"
|
||||||
|
else
|
||||||
|
export _H2="X-DNS-Token: $EXOSCALE_API_KEY:$EXOSCALE_SECRET_KEY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$data" ] || [ "$method" = "DELETE" ]; then
|
||||||
|
export _H3="Content-Type: application/json"
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$request_url" "" "$method")"
|
||||||
|
else
|
||||||
|
response="$(_get "$request_url" "" "" "$method")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $request_url"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
|
#Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
|
||||||
|
|
||||||
LINODE_API_URL="https://api.linode.com/v4/domains"
|
LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action="
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -27,14 +27,10 @@ dns_linode_add() {
|
|||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
_payload="{
|
_parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue"
|
||||||
\"type\": \"TXT\",
|
|
||||||
\"name\": \"$_sub_domain\",
|
|
||||||
\"target\": \"$txtvalue\"
|
|
||||||
}"
|
|
||||||
|
|
||||||
if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then
|
if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then
|
||||||
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||||
_debug _resource_id "$_resource_id"
|
_debug _resource_id "$_resource_id"
|
||||||
|
|
||||||
if [ -z "$_resource_id" ]; then
|
if [ -z "$_resource_id" ]; then
|
||||||
@ -69,21 +65,25 @@ dns_linode_rm() {
|
|||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then
|
_parameters="&DomainID=$_domain_id"
|
||||||
|
|
||||||
|
if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then
|
||||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||||
|
|
||||||
resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")"
|
resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")"
|
||||||
if [ "$resource" ]; then
|
if [ "$resource" ]; then
|
||||||
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||||
if [ "$_resource_id" ]; then
|
if [ "$_resource_id" ]; then
|
||||||
_debug _resource_id "$_resource_id"
|
_debug _resource_id "$_resource_id"
|
||||||
|
|
||||||
if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then
|
_parameters="&DomainID=$_domain_id&ResourceID=$_resource_id"
|
||||||
# On 200/OK, empty set is returned. Check for error, if any.
|
|
||||||
_error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
|
||||||
|
|
||||||
if [ -n "$_error_response" ]; then
|
if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then
|
||||||
_err "Error deleting the domain resource: $_error_response"
|
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||||
|
_debug _resource_id "$_resource_id"
|
||||||
|
|
||||||
|
if [ -z "$_resource_id" ]; then
|
||||||
|
_err "Error deleting the domain resource."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ _get_root() {
|
|||||||
i=2
|
i=2
|
||||||
p=1
|
p=1
|
||||||
|
|
||||||
if _rest GET; then
|
if _rest GET "domain.list"; then
|
||||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||||
while true; do
|
while true; do
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
@ -137,9 +137,9 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")"
|
hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")"
|
||||||
if [ "$hostedzone" ]; then
|
if [ "$hostedzone" ]; then
|
||||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||||
if [ "$_domain_id" ]; then
|
if [ "$_domain_id" ]; then
|
||||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
_domain=$h
|
_domain=$h
|
||||||
@ -165,7 +165,6 @@ _rest() {
|
|||||||
|
|
||||||
export _H1="Accept: application/json"
|
export _H1="Accept: application/json"
|
||||||
export _H2="Content-Type: application/json"
|
export _H2="Content-Type: application/json"
|
||||||
export _H3="Authorization: Bearer $LINODE_API_KEY"
|
|
||||||
|
|
||||||
if [ "$mtd" != "GET" ]; then
|
if [ "$mtd" != "GET" ]; then
|
||||||
# both POST and DELETE.
|
# both POST and DELETE.
|
||||||
|
185
dnsapi/dns_linode_v4.sh
Executable file
185
dnsapi/dns_linode_v4.sh
Executable file
@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#Original Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
|
||||||
|
#v4 Update Author: Aaron W. Swenson <aaron@grandmasfridge.org>
|
||||||
|
|
||||||
|
LINODE_V4_API_URL="https://api.linode.com/v4/domains"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_linode_add() {
|
||||||
|
fulldomain="${1}"
|
||||||
|
txtvalue="${2}"
|
||||||
|
|
||||||
|
if ! _Linode_API; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Using Linode"
|
||||||
|
_debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'"
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "Domain does not exist."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_payload="{
|
||||||
|
\"type\": \"TXT\",
|
||||||
|
\"name\": \"$_sub_domain\",
|
||||||
|
\"target\": \"$txtvalue\"
|
||||||
|
}"
|
||||||
|
|
||||||
|
if _rest POST "/$_domain_id/records" "$_payload" && [ -n "$response" ]; then
|
||||||
|
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||||
|
_debug _resource_id "$_resource_id"
|
||||||
|
|
||||||
|
if [ -z "$_resource_id" ]; then
|
||||||
|
_err "Error adding the domain resource."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Domain resource successfully added."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: dns_linode_rm _acme-challenge.www.domain.com
|
||||||
|
dns_linode_rm() {
|
||||||
|
fulldomain="${1}"
|
||||||
|
|
||||||
|
if ! _Linode_API; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Using Linode"
|
||||||
|
_debug "Calling: dns_linode_rm() '${fulldomain}'"
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "Domain does not exist."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
if _rest GET "/$_domain_id/records" && [ -n "$response" ]; then
|
||||||
|
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||||
|
|
||||||
|
resource="$(echo "$response" | _egrep_o "{.*\"name\":\s*\"$_sub_domain\".*}")"
|
||||||
|
if [ "$resource" ]; then
|
||||||
|
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||||
|
if [ "$_resource_id" ]; then
|
||||||
|
_debug _resource_id "$_resource_id"
|
||||||
|
|
||||||
|
if _rest DELETE "/$_domain_id/records/$_resource_id" && [ -n "$response" ]; then
|
||||||
|
# On 200/OK, empty set is returned. Check for error, if any.
|
||||||
|
_error_response=$(printf "%s\n" "$response" | _egrep_o "\"errors\"" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||||
|
|
||||||
|
if [ -n "$_error_response" ]; then
|
||||||
|
_err "Error deleting the domain resource: $_error_response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Domain resource successfully deleted."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
|
_Linode_API() {
|
||||||
|
if [ -z "$LINODE_V4_API_KEY" ]; then
|
||||||
|
LINODE_V4_API_KEY=""
|
||||||
|
|
||||||
|
_err "You didn't specify the Linode v4 API key yet."
|
||||||
|
_err "Please create your key and try again."
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf LINODE_V4_API_KEY "$LINODE_V4_API_KEY"
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
#_acme-challenge.www.domain.com
|
||||||
|
#returns
|
||||||
|
# _sub_domain=_acme-challenge.www
|
||||||
|
# _domain=domain.com
|
||||||
|
# _domain_id=12345
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
i=2
|
||||||
|
p=1
|
||||||
|
|
||||||
|
if _rest GET; then
|
||||||
|
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||||
|
while true; do
|
||||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug h "$h"
|
||||||
|
if [ -z "$h" ]; then
|
||||||
|
#not valid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
hostedzone="$(echo "$response" | _egrep_o "{.*\"domain\":\s*\"$h\".*}")"
|
||||||
|
if [ "$hostedzone" ]; then
|
||||||
|
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _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
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#method method action data
|
||||||
|
_rest() {
|
||||||
|
mtd="$1"
|
||||||
|
ep="$2"
|
||||||
|
data="$3"
|
||||||
|
|
||||||
|
_debug mtd "$mtd"
|
||||||
|
_debug ep "$ep"
|
||||||
|
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
export _H2="Content-Type: application/json"
|
||||||
|
export _H3="Authorization: Bearer $LINODE_V4_API_KEY"
|
||||||
|
|
||||||
|
if [ "$mtd" != "GET" ]; then
|
||||||
|
# both POST and DELETE.
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$LINODE_V4_API_URL$ep" "" "$mtd")"
|
||||||
|
else
|
||||||
|
response="$(_get "$LINODE_V4_API_URL$ep$data")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
@ -13,12 +13,24 @@ dns_nsupdate_add() {
|
|||||||
_saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}"
|
_saveaccountconf NSUPDATE_SERVER "${NSUPDATE_SERVER}"
|
||||||
_saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}"
|
_saveaccountconf NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}"
|
||||||
_saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}"
|
_saveaccountconf NSUPDATE_KEY "${NSUPDATE_KEY}"
|
||||||
|
_saveaccountconf NSUPDATE_ZONE "${NSUPDATE_ZONE}"
|
||||||
_info "adding ${fulldomain}. 60 in txt \"${txtvalue}\""
|
_info "adding ${fulldomain}. 60 in txt \"${txtvalue}\""
|
||||||
nsupdate -k "${NSUPDATE_KEY}" <<EOF
|
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d"
|
||||||
|
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D"
|
||||||
|
if [ -z "${NSUPDATE_ZONE}" ]; then
|
||||||
|
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
|
||||||
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
||||||
update add ${fulldomain}. 60 in txt "${txtvalue}"
|
update add ${fulldomain}. 60 in txt "${txtvalue}"
|
||||||
send
|
send
|
||||||
EOF
|
EOF
|
||||||
|
else
|
||||||
|
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
|
||||||
|
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
||||||
|
zone ${NSUPDATE_ZONE}.
|
||||||
|
update add ${fulldomain}. 60 in txt "${txtvalue}"
|
||||||
|
send
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
_err "error updating domain"
|
_err "error updating domain"
|
||||||
return 1
|
return 1
|
||||||
@ -34,11 +46,22 @@ dns_nsupdate_rm() {
|
|||||||
[ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost"
|
[ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost"
|
||||||
[ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53
|
[ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53
|
||||||
_info "removing ${fulldomain}. txt"
|
_info "removing ${fulldomain}. txt"
|
||||||
nsupdate -k "${NSUPDATE_KEY}" <<EOF
|
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d"
|
||||||
|
[ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D"
|
||||||
|
if [ -z "${NSUPDATE_ZONE}" ]; then
|
||||||
|
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
|
||||||
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
||||||
update delete ${fulldomain}. txt
|
update delete ${fulldomain}. txt
|
||||||
send
|
send
|
||||||
EOF
|
EOF
|
||||||
|
else
|
||||||
|
nsupdate -k "${NSUPDATE_KEY}" $nsdebug <<EOF
|
||||||
|
server ${NSUPDATE_SERVER} ${NSUPDATE_SERVER_PORT}
|
||||||
|
zone ${NSUPDATE_ZONE}.
|
||||||
|
update delete ${fulldomain}. txt
|
||||||
|
send
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
_err "error updating domain"
|
_err "error updating domain"
|
||||||
return 1
|
return 1
|
||||||
|
Loading…
Reference in New Issue
Block a user