This repository has been archived by the owner on Feb 6, 2025. It is now read-only.
forked from scribe777/letsencrypt-namecheap-dns-auth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathletsencrypt-namecheap-dns-auth.sh
executable file
·172 lines (146 loc) · 6.52 KB
/
letsencrypt-namecheap-dns-auth.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/bin/bash
####### !!!!!!!!!!!!! W A R N I N G !!!!!!!!!!!!! #######
#
# NameCheap only has an API for setting all host DNS records
# i.e., we can't simply update one TXT row
#
# That forces the workflow of this script to:
# first read in all host records,
# leave out any old _acme-challenge records
# add our new certbot _acme-challenge record
# REPLACE ALL HOST DNS RECORDS
#
# This sounds dangerous and probably is! I took a screenshot
# of my existing NameCheap DNS entries before running this script
# in case it didn't preserve something.
# I personally wouldn't trust my script on a domain which had
# more than 10 records. This means the update URL gets pretty long
# and AGAIN WANT TO ENCOURAGE YOU TO TAKE A SCREENSHOT OF YOUR DNS
# CONFIGURATION AND CHECK IT AFTER RUNNING THIS SCRIPT
#
# ALSO, NameCheap recommends creating a sandbox account and
# testing there. I would suggest doing this.
# You can run this script directly, instead of from certbot
# if you fill in a couple extra variables, as mentioned in
# the SANDBOX section below.
# QuickStart: Don't quickstart. Read everything up to this point first.
# You'll need the wget and dig commands available
# Enable API access on your NameCheap Account and obtain your APIKey
# In NameCheap's API section, whitelist the IP of the server
# from where you will run this script
# Configure this script with your NameCheap userID, APIKey, and whitelisted IP address
#
# TEST THIS SCRIPT BY CONFIGURING IT TO A SANDBOX ACCOUNT YOU'VE SETUP AT:
# https://ap.www.sandbox.namecheap.com/
# (see SANDBOX section below)
#
# provide this script to certbot-2 when renewing, e.g.,
# certbot-2 renew --manual-auth-hook=/root/letsencrypt-namecheap-dns-auth.sh
#
# Probably put the above command in a monthly cron job
#
# Best wishes,
# Troy A. Griffitts <[email protected]>
# https://crosswire.org
#
#
# START OF SCARY SCRIPT ----------------------------------------------------
#
# ------- certbot will pass us these variables -------
#
# CERTBOT_DOMAIN: The domain being authenticated
# CERTBOT_VALIDATION: The validation string
# CERTBOT_TOKEN: Resource name part of the HTTP-01 challenge (HTTP-01 only)
# CERTBOT_REMAINING_CHALLENGES: Number of challenges remaining after the current challenge
# CERTBOT_ALL_DOMAINS: A comma-separated list of all domains challenged for the current
# NameCheap's production API service base
SERVICEURL="https://api.namecheap.com/xml.response"
# --------------- Start configurable section --------------------------------
# your NameCheap login ID
# (their docs mention both API User and NC User, but they are the same
# in our scenario because we are editing our own records and not one of our 'clients')
# NCUSER=myUserID
# your whitelisted IP address
# CLIENTIP=8.8.8.8
# your API Key
# NCAPIKEY=9zzzzzzzzzzzzzzzzzzzzzzzzzzzzzf4
#
# SANDBOX TESTING
#
# For sandbox testing first, you'll probably want to override some of these
# then you can just run the script directly and see if you preserve
# all your other host records and get the new acme validation TXT record
# with the dummy value you specify below
#
#SERVICEURL="https://api.sandbox.namecheap.com/xml.response"
#NCAPIKEY=2czzzzzzzzzzzzzzzzzzzzzzzzzzzz1c
# CERTBOT_DOMAIN=test.userdomain.com
# CERTBOT_VALIDATION=abc
# number of seconds to wait between checks for our certbot validation records to finish propagation
WAITSECONDS=10
# if we are running a local bind server to cache DNS entries, we probably want to flush our cache
# between each check for our challenge certificate
FLUSH_LOCAL_BIND_SERVER=false
# --------------- End configurable section --------------------------------
# Let's grab all our current DNS records
TLD=$(echo ${CERTBOT_DOMAIN} | rev | cut -d. -f1 | rev)
SLD=$(echo ${CERTBOT_DOMAIN} | rev | cut -d. -f2 | rev)
HOST=$(echo ${CERTBOT_DOMAIN} | rev | cut -d. -f3- | rev)
if [[ -z "$HOST" || "$HOST" == "*" ]]; then
CHALLENGE_HOST="_acme-challenge"
else
CHALLENGE_HOST="_acme-challenge.${HOST}"
fi
echo $CHALLENGE_HOST
APICOMMAND="namecheap.domains.dns.getHosts&SLD=${SLD}&TLD=${TLD}"
wget -O /tmp/getHosts.xml "${SERVICEURL}?ClientIp=${CLIENTIP}&ApiUser=${NCUSER}&ApiKey=${NCAPIKEY}&UserName=${NCUSER}&Command=${APICOMMAND}"
APICOMMAND="namecheap.domains.dns.setHosts&SLD=${SLD}&TLD=${TLD}"
ENTRYNUM=1
while IFS= read -r line; do
NAME=$(echo $line | sed 's/^.* Name="\([^"]*\)".*$/\1/g')
TYPE=$(echo $line | sed 's/^.* Type="\([^"]*\)".*$/\1/g')
ADDRESS=$(echo $line | sed 's/^.* Address="\([^"]*\)".*$/\1/g')
MXPREF=$(echo $line | sed 's/^.* MXPref="\([^"]*\)".*$/\1/g')
TTL=$(echo $line | sed 's/^.* TTL="\([^"]*\)".*$/\1/g')
# apparently 1799 is "auto"
# if we specify what we received in getHosts, we don't preserve 'auto'
# so we are specifying auto here
TTL=1799
if [[ "${NAME}" == "_acme-challenge" ]]; then
# skip all existing _acme-challenge entries
true
else
APICOMMAND="${APICOMMAND}&HostName${ENTRYNUM}=${NAME}&RecordType${ENTRYNUM}=${TYPE}&Address${ENTRYNUM}=${ADDRESS}&MXPref${ENTRYNUM}=${MXPREF}&TTL${ENTRYNUM}=${TTL}"
ENTRYNUM=$((${ENTRYNUM} + 1))
fi
done <<<"$(grep "<host " /tmp/getHosts.xml)"
# OK, now let's add our new acme challenge verification record
APICOMMAND="${APICOMMAND}&HostName${ENTRYNUM}=${CHALLENGE_HOST}&RecordType${ENTRYNUM}=TXT&Address${ENTRYNUM}=${CERTBOT_VALIDATION}"
# Finally, we'll update all host DNS records
# echo "${SERVICEURL}?ClientIp=${CLIENTIP}&ApiUser=${NCUSER}&ApiKey=${NCAPIKEY}&UserName=${NCUSER}&Command=${APICOMMAND}"
wget -O /tmp/testapi.out "${SERVICEURL}?ClientIp=${CLIENTIP}&ApiUser=${NCUSER}&ApiKey=${NCAPIKEY}&UserName=${NCUSER}&Command=${APICOMMAND}"
# Actually, FINALLY, we need to wait for our records to propagate before letting certbot continue.
# Because we "echo" output here, certbot thinks something might have gone wrong. It doesn't effect
# the successful completion of the domain cert renewal. I like to see the output. You might rather like to
# see certbot think everything went perfect and comment out the "echo" lines below.
FOUND=false
while [[ "${FOUND}" != "true" ]]; do
echo "Sleeping for ${WAITSECONDS} seconds..."
sleep ${WAITSECONDS}
if [[ "${FLUSH_LOCAL_BIND_SERVER}" == "true" ]]; then
rndc flush
rndc reload
fi
CURRENT_ACME_VALIDATION=$(dig -t TXT ${CHALLENGE_HOST}.${SLD}.${TLD} | grep "^${CHALLENGE_HOST}.${SLD}.${TLD}." | cut -d\" -f 2)
if [[ "${CERTBOT_VALIDATION}" == "${CURRENT_ACME_VALIDATION}" ]]; then
FOUND=true
echo "Found!"
sleep ${WAITSECONDS}
else
echo "Not yet found."
fi
done
# cleanup
# comment out these lines if you want to see some output from our commands, above
rm -f /tmp/testapi.out
rm -f /tmp/getHosts.xml