Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DNS API support for Nexcess, Thermo.io, and Futurehosting #1812

Closed
wants to merge 15 commits into from
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ 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.**

Expand All @@ -277,7 +277,7 @@ 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.**

Expand Down Expand Up @@ -349,6 +349,9 @@ You don't have to do anything manually!
1. Neodigit.net API (https://www.neodigit.net)
1. Exoscale.com API (https://www.exoscale.com/)
1. PointDNS API (https://pointhq.com/)
1. Nexcess API (https://www.nexcess.net)
1. Thermo.io API (https://www.thermo.io)
1. Futurehosting API (https://www.futurehosting.com)

And:

Expand Down Expand Up @@ -526,5 +529,5 @@ Please Star and Fork me.
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)
61 changes: 58 additions & 3 deletions dnsapi/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# How to use DNS API

If your dns provider doesn't provide api access, you can use our dns alias mode:
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

Expand Down Expand Up @@ -891,7 +891,7 @@ 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.
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

```
Expand Down Expand Up @@ -1011,9 +1011,10 @@ 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
Expand Down Expand Up @@ -1139,6 +1140,60 @@ You can then issue certs by using:
```acme.sh --issue --dns dns_pointhq -d example.com -d www.example.com
```

## 59. 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 NEXCESS_API_TOKEN="YOUR_TOKEN_HERE"
```

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_nexcess -d example.com --dnssleep 900
```

The `NEXCESS_API_TOKEN will be saved in `~/.acme.sh/account.conf` and will be reused when needed.

## 60. 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 THERMO_API_TOKEN="YOUR_TOKEN_HERE"
```

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_thermo -d example.com --dnssleep 900
```

The `THERMO_API_TOKEN will be saved in `~/.acme.sh/account.conf` and will be reused when needed.

## 61. 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 FH_API_TOKEN="YOUR_TOKEN_HERE"
```

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_fh -d example.com --dnssleep 900
```

The `FH_API_TOKEN will be saved in `~/.acme.sh/account.conf` and will be reused when needed.

# Use custom API

If your API is not supported yet, you can write your own DNS API.
Expand Down
189 changes: 189 additions & 0 deletions dnsapi/dns_fh.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#!/usr/bin/env sh
########################################################################
# Futurehosting script for acme.sh
#
# Environment variables:
#
# - FH_API_TOKEN (your Futurehosting API Token)
# Note: If you do not have an API token, one can be generated at:
# https://my.futurehosting.com/api-token
#
# Author: Frank Laszlo <[email protected]>

FH_API_URL="https://my.futurehosting.com/"
FH_API_VERSION="0"

# dns_fh_add() - Add TXT record
# Usage: dns_fh_add _acme-challenge.subdomain.domain.com "XyZ123..."
dns_fh_add() {
host="${1}"
txtvalue="${2}"

_debug host "${host}"
_debug txtvalue "${txtvalue}"

if ! _check_fh_api_token; then
return 1
fi

_info "Using Futurehosting"
_debug "Calling: dns_fh_add() '${host}' '${txtvalue}'"

_debug "Detecting root zone"
if ! _get_root "${host}"; then
_err "Zone for domain does not exist."
return 1
fi
_debug _zone_id "${_zone_id}"
_debug _sub_domain "${_sub_domain}"
_debug _domain "${_domain}"

_post_data="{\"zone_id\": \"${_zone_id}\", \"type\": \"TXT\", \"host\": \"${host}\", \"target\": \"${txtvalue}\", \"ttl\": \"300\"}"

if _rest POST "dns-record" "${_post_data}" && [ -n "${response}" ]; then
_record_id=$(printf "%s\n" "${response}" | _egrep_o "\"record_id\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
laszlof marked this conversation as resolved.
Show resolved Hide resolved
_debug _record_id "${_record_id}"

if [ -z "$_record_id" ]; then
_err "Error adding the TXT record."
return 1
fi

_info "TXT record successfully added."
return 0
fi

return 1
}

# dns_fh_rm() - Remove TXT record
# Usage: dns_fh_rm _acme-challenge.subdomain.domain.com "XyZ123..."
dns_fh_rm() {
host="${1}"
txtvalue="${2}"

_debug host "${host}"
_debug txtvalue "${txtvalue}"

if ! _check_fh_api_token; then
return 1
fi

_info "Using Futurehosting"
_debug "Calling: dns_fh_rm() '${host}'"

_debug "Detecting root zone"
if ! _get_root "${host}"; then
_err "Zone for domain does not exist."
return 1
fi
_debug _zone_id "${_zone_id}"
_debug _sub_domain "${_sub_domain}"
_debug _domain "${_domain}"

_parameters="?zone_id=${_zone_id}"

if _rest GET "dns-record" "${_parameters}" && [ -n "${response}" ]; then
response="$(echo "${response}" | tr -d "\n" | sed 's/^\[\(.*\)\]$/\1/' | sed -e 's/{"record_id":/|"record_id":/g' | sed 's/|/&{/g' | tr "|" "\n")"
_debug response "${response}"

record="$(echo "${response}" | _egrep_o "{.*\"host\":\s*\"${_sub_domain}\",\s*\"target\":\s*\"${txtvalue}\".*}")"
_debug record "${record}"

if [ "${record}" ]; then
_record_id=$(printf "%s\n" "${record}" | _egrep_o "\"record_id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
if [ "${_record_id}" ]; then
_debug _record_id "${_record_id}"

_rest DELETE "dns-record/${_record_id}"

_info "TXT record successfully deleted."
return 0
fi

return 1
fi

return 0
fi

return 1
}

_check_fh_api_token() {
if [ -z "${FH_API_TOKEN}" ]; then
FH_API_TOKEN="${FH_API_TOKEN:-$(_readaccountconf FH_API_TOKEN)}"
laszlof marked this conversation as resolved.
Show resolved Hide resolved

_err "You have not defined your FH_API_TOKEN."
_err "Please create your token and try again."
_err "If you need to generate a new token, please visit:"
_err "https://portal.fh.net/api-token"

return 1
fi

_saveaccountconf FH_API_TOKEN "${FH_API_TOKEN}"
}

_get_root() {
domain="${1}"
i=2
p=1

if _rest GET "dns-zone"; then
response="$(echo "${response}" | tr -d "\n" | sed 's/^\[\(.*\)\]$/\1/' | sed -e 's/{"zone_id":/|"zone_id":/g' | sed 's/|/&{/g' | tr "|" "\n")"

_debug response "${response}"
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
_zone_id=$(printf "%s\n" "${hostedzone}" | _egrep_o "\"zone_id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
if [ "${_zone_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
}

_rest() {
method="${1}"
ep="${2}"
data="${3}"

_debug method "${method}"
_debug ep "${ep}"

export _H1="Accept: application/json"
export _H2="Content-Type: application/json"
export _H3="Api-Version: ${FH_API_VERSION}"
export _H4="User-Agent: FH-ACME-CLIENT"
export _H5="Authorization: Bearer ${FH_API_TOKEN}"

if [ "${method}" != "GET" ]; then
_debug data "${data}"
response="$(_post "${data}" "${FH_API_URL}${ep}" "" "${method}")"
else
response="$(_get "${FH_API_URL}${ep}${data}")"
fi

if [ "${?}" != "0" ]; then
_err "error ${ep}"
return 1
fi
_debug2 response "${response}"
return 0
}
Loading