diff --git a/Dockerfile b/Dockerfile
index feb89b0d..4cb33139 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,17 +4,17 @@ RUN apk update -f \
&& apk --no-cache add -f \
openssl \
curl \
- netcat-openbsd
+ netcat-openbsd \
+ && rm -rf /var/cache/apk/*
ENV LE_CONFIG_HOME /acme.sh
ENV AUTO_UPGRADE 1
#Install
-RUN mkdir -p /install_acme.sh/
ADD ./ /install_acme.sh/
-RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh)
-RUN rm -rf /install_acme.sh/
+RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
+
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh
@@ -55,5 +55,7 @@ else \n \
/root/.acme.sh/acme.sh --config-home /acme.sh \"\$@\"\n \
fi" >/entry.sh && chmod +x /entry.sh
+VOLUME /acme.sh
+
ENTRYPOINT ["/entry.sh"]
CMD ["--help"]
diff --git a/README.md b/README.md
index 0cb800eb..afdda8a8 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
# An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)
+
+[![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- An ACME protocol client written purely in Shell (Unix shell) language.
- Full ACME protocol implementation.
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
@@ -8,6 +10,7 @@
- Just one script to issue, renew and install your certificates automatically.
- DOES NOT require `root/sudoer` access.
- Docker friendly
+- IPv6 support
It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
@@ -304,17 +307,14 @@ You don't have to do anything manually!
1. CloudFlare.com API
1. DNSPod.cn API
-1. DNSimple API
1. CloudXNS.com API
1. GoDaddy.com API
-1. OVH, kimsufi, soyoustart and runabove API
-1. AWS Route 53
1. PowerDNS.com API
-1. 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.)
+1. OVH, kimsufi, soyoustart and runabove API
+1. nsupdate API
1. LuaDNS.com API
1. DNSMadeEasy.com API
-1. nsupdate API
+1. AWS Route 53
1. aliyun.com(阿里云) API
1. ISPConfig 3.1 API
1. Alwaysdata.com API
@@ -329,8 +329,18 @@ You don't have to do anything manually!
1. Infoblox NIOS API (https://www.infoblox.com/)
1. VSCALE (https://vscale.io/)
1. Dynu API (https://www.dynu.com)
+1. DNSimple API
+1. NS1.com API
+
+
+
+And:
+
+1. 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.)
+
**More APIs coming soon...**
If your DNS provider is not on the supported list above, you can write your own DNS API script easily. If you do, please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute it to the project.
diff --git a/acme.sh b/acme.sh
index 7ce947ea..8edf2c61 100755
--- a/acme.sh
+++ b/acme.sh
@@ -444,19 +444,27 @@ if [ "$(printf '\x41')" != 'A' ]; then
fi
_h2b() {
+ if _exists xxd; then
+ xxd -r -p
+ return
+ fi
+
hex=$(cat)
i=1
j=2
-
- _debug3 _URGLY_PRINTF "$_URGLY_PRINTF"
- while true; do
- if [ -z "$_URGLY_PRINTF" ]; then
+ _debug2 _URGLY_PRINTF "$_URGLY_PRINTF"
+ if [ -z "$_URGLY_PRINTF" ]; then
+ while true; do
h="$(printf "%s" "$hex" | cut -c $i-$j)"
if [ -z "$h" ]; then
break
fi
printf "\x$h%s"
- else
+ i="$(_math "$i" + 2)"
+ j="$(_math "$j" + 2)"
+ done
+ else
+ while true; do
ic="$(printf "%s" "$hex" | cut -c $i)"
jc="$(printf "%s" "$hex" | cut -c $j)"
if [ -z "$ic$jc" ]; then
@@ -465,12 +473,11 @@ _h2b() {
ic="$(_h_char_2_dec "$ic")"
jc="$(_h_char_2_dec "$jc")"
printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
- fi
-
- i="$(_math "$i" + 2)"
- j="$(_math "$j" + 2)"
+ i="$(_math "$i" + 2)"
+ j="$(_math "$j" + 2)"
+ done
+ fi
- done
}
_is_solaris() {
@@ -1244,17 +1251,20 @@ createDomainKey() {
fi
domain=$1
- length=$2
+ _cdl=$2
- if [ -z "$length" ]; then
+ if [ -z "$_cdl" ]; then
_debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH"
- length="$DEFAULT_DOMAIN_KEY_LENGTH"
+ _cdl="$DEFAULT_DOMAIN_KEY_LENGTH"
fi
- _initpath "$domain" "$length"
+ _initpath "$domain" "$_cdl"
if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then
- _createkey "$length" "$CERT_KEY_PATH"
+ if _createkey "$_cdl" "$CERT_KEY_PATH"; then
+ _savedomainconf Le_Keylength "$_cdl"
+ _info "The domain key is here: $(__green $CERT_KEY_PATH)"
+ fi
else
if [ "$IS_RENEW" ]; then
_info "Domain key exists, skip"
diff --git a/dnsapi/README.md b/dnsapi/README.md
index f53d8ad4..dff62399 100644
--- a/dnsapi/README.md
+++ b/dnsapi/README.md
@@ -494,6 +494,17 @@ be reused when needed.
If you have any issues with this integration please report them to
https://github.com/pho3nixf1re/acme.sh/issues.
+## 26. Use NS1.com API
+
+```
+export NS1_Key="fdmlfsdklmfdkmqsdfk"
+```
+
+Ok, let's issue a cert now:
+```
+acme.sh --issue --dns dns_nsone -d example.com -d www.example.com
+```
+
# Use custom API
If your API is not supported yet, you can write your own DNS API.
diff --git a/dnsapi/dns_aws.sh b/dnsapi/dns_aws.sh
index 21e86686..800c3d09 100755
--- a/dnsapi/dns_aws.sh
+++ b/dnsapi/dns_aws.sh
@@ -106,7 +106,7 @@ _get_root() {
fi
if _contains "$response" "$h."; then
- hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*<.HostedZone>")"
+ hostedzone="$(echo "$response" | sed 's//#&/g' | tr '#' '\n' | _egrep_o "[^<]*<.Id>$h.<.Name>.*false<.PrivateZone>.*<.HostedZone>")"
_debug hostedzone "$hostedzone"
if [ -z "$hostedzone" ]; then
_err "Error, can not get hostedzone."
diff --git a/dnsapi/dns_gandi_livedns.sh b/dnsapi/dns_gandi_livedns.sh
index 28b8f99d..82ed599c 100755
--- a/dnsapi/dns_gandi_livedns.sh
+++ b/dnsapi/dns_gandi_livedns.sh
@@ -37,7 +37,7 @@ dns_gandi_livedns_add() {
_debug sub_domain "$_sub_domain"
_gandi_livedns_rest PUT "domains/$_domain/records/$_sub_domain/TXT" "{\"rrset_ttl\": 300, \"rrset_values\":[\"$txtvalue\"]}" \
- && _contains "$response" '{"message": "Zone Record Created"}' \
+ && _contains "$response" '{"message": "DNS Record Created"}' \
&& _info "Add $(__green "success")"
}
diff --git a/dnsapi/dns_nsone.sh b/dnsapi/dns_nsone.sh
new file mode 100644
index 00000000..adf1f422
--- /dev/null
+++ b/dnsapi/dns_nsone.sh
@@ -0,0 +1,158 @@
+#!/usr/bin/env sh
+
+# bug reports to dev@1e.ca
+
+#
+#NS1_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
+#
+
+NS1_Api="https://api.nsone.net/v1"
+
+######## Public functions #####################
+
+#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
+dns_nsone_add() {
+ fulldomain=$1
+ txtvalue=$2
+
+ if [ -z "$NS1_Key" ]; then
+ NS1_Key=""
+ _err "You didn't specify nsone dns api key yet."
+ _err "Please create you key and try again."
+ return 1
+ fi
+
+ #save the api key and email to the account conf file.
+ _saveaccountconf NS1_Key "$NS1_Key"
+
+ _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"
+ _nsone_rest GET "zones/${_domain}"
+
+ if ! _contains "$response" "\"records\":"; then
+ _err "Error"
+ return 1
+ fi
+
+ count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",[^{]*\"type\":\"TXT\"" | wc -l | tr -d " ")
+ _debug count "$count"
+ if [ "$count" = "0" ]; then
+ _info "Adding record"
+
+ if _nsone_rest PUT "zones/$_domain/$fulldomain/TXT" "{\"answers\":[{\"answer\":[\"$txtvalue\"]}],\"type\":\"TXT\",\"domain\":\"$fulldomain\",\"zone\":\"$_domain\"}"; then
+ if _contains "$response" "$fulldomain"; then
+ _info "Added"
+ #todo: check if the record takes effect
+ return 0
+ else
+ _err "Add txt record error."
+ return 1
+ fi
+ fi
+ _err "Add txt record error."
+ else
+ _info "Updating record"
+ record_id=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain.\",[^{]*\"type\":\"TXT\",\"id\":\"[^,]*\"" | _head_n 1 | cut -d: -f7 | cut -d, -f1)
+ _debug "record_id" "$record_id"
+
+ _nsone_rest POST "zones/$_domain/$fulldomain/TXT" "{\"answers\": [{\"answer\": [\"$txtvalue\"]}],\"type\": \"TXT\",\"domain\":\"$fulldomain\",\"zone\": \"$_domain\"}"
+ if [ "$?" = "0" ] && _contains "$response" "$fulldomain"; then
+ _info "Updated!"
+ #todo: check if the record takes effect
+ return 0
+ fi
+ _err "Update error"
+ return 1
+ fi
+
+}
+
+#fulldomain
+dns_nsone_rm() {
+ fulldomain=$1
+ txtvalue=$2
+ _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"
+ _nsone_rest GET "zones/${_domain}/$fulldomain/TXT"
+
+ count=$(printf "%s\n" "$response" | _egrep_o "\"domain\":\"$fulldomain\",.*\"type\":\"TXT\"" | wc -l | tr -d " ")
+ _debug count "$count"
+ if [ "$count" = "0" ]; then
+ _info "Don't need to remove."
+ else
+ if ! _nsone_rest DELETE "zones/${_domain}/$fulldomain/TXT"; then
+ _err "Delete record error."
+ return 1
+ fi
+ _contains "$response" ""
+ fi
+}
+
+#################### Private functions below ##################################
+#_acme-challenge.www.domain.com
+#returns
+# _sub_domain=_acme-challenge.www
+# _domain=domain.com
+# _domain_id=sdjkglgdfewsdfg
+_get_root() {
+ domain=$1
+ i=2
+ p=1
+ if ! _nsone_rest GET "zones"; then
+ return 1
+ fi
+ 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" "\"zone\":\"$h\""; 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
+}
+
+_nsone_rest() {
+ m=$1
+ ep="$2"
+ data="$3"
+ _debug "$ep"
+
+ export _H1="Accept: application/json"
+ export _H2="X-NSONE-Key: $NS1_Key"
+ if [ "$m" != "GET" ]; then
+ _debug data "$data"
+ response="$(_post "$data" "$NS1_Api/$ep" "" "$m")"
+ else
+ response="$(_get "$NS1_Api/$ep")"
+ fi
+
+ if [ "$?" != "0" ]; then
+ _err "error $ep"
+ return 1
+ fi
+ _debug2 response "$response"
+ return 0
+}