Skip to content

Commit e566691

Browse files
Add Support for challenge validation plugin hooks
1 parent be35b55 commit e566691

File tree

5 files changed

+509
-12
lines changed

5 files changed

+509
-12
lines changed

README.md

+35-11
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ https://github.com/acmesh-official/acmetest
114114
- DNS mode
115115
- [DNS alias mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode)
116116
- [Stateless mode](https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode)
117+
- [HTTP API mode](https://github.com/acmesh-official/acme.sh/wiki/HTTP-API)
117118

118119

119120
# 1. How to install
@@ -358,7 +359,30 @@ Ok, it's done.
358359

359360
**Please use dns api mode instead.**
360361

361-
# 10. Issue ECC certificates
362+
# 10. Use HTTP API mode
363+
364+
If you want to deploy the challenge files using an external method like SCP or FTPS, you can use the HTTP API mode:
365+
366+
```bash
367+
acme.sh --issue -d example.com --httpapi scp
368+
```
369+
370+
You'll need to configure the required environment variables first:
371+
372+
```bash
373+
# For SCP plugin
374+
export HTTP_SCP_USER="username"
375+
export HTTP_SCP_HOST="example.com"
376+
export HTTP_SCP_PATH="/var/www/html"
377+
```
378+
379+
Available HTTP API plugins:
380+
- `scp`: Deploy challenge files via SCP
381+
- `ftps`: Deploy challenge files via FTPS
382+
383+
More information: [HTTP API mode](https://github.com/acmesh-official/acme.sh/wiki/HTTP-API)
384+
385+
# 11. Issue ECC certificates
362386

363387
Just set the `keylength` parameter with a prefix `ec-`.
364388

@@ -388,7 +412,7 @@ Valid values are:
388412
6. **4096 (RSA4096)**
389413

390414

391-
# 11. Issue Wildcard certificates
415+
# 12. Issue Wildcard certificates
392416

393417
It's simple, just give a wildcard domain as the `-d` parameter.
394418

@@ -398,7 +422,7 @@ acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf
398422

399423

400424

401-
# 12. How to renew the certs
425+
# 13. How to renew the certs
402426

403427
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
404428

@@ -415,7 +439,7 @@ acme.sh --renew -d example.com --force --ecc
415439
```
416440

417441

418-
# 13. How to stop cert renewal
442+
# 14. How to stop cert renewal
419443

420444
To stop renewal of a cert, you can execute the following to remove the cert from the renewal list:
421445

@@ -428,7 +452,7 @@ The cert/key file is not removed from the disk.
428452
You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself.
429453

430454

431-
# 14. How to upgrade `acme.sh`
455+
# 15. How to upgrade `acme.sh`
432456

433457
acme.sh is in constant development, so it's strongly recommended to use the latest code.
434458

@@ -453,24 +477,24 @@ acme.sh --upgrade --auto-upgrade 0
453477
```
454478

455479

456-
# 15. Issue a cert from an existing CSR
480+
# 16. Issue a cert from an existing CSR
457481

458482
https://github.com/acmesh-official/acme.sh/wiki/Issue-a-cert-from-existing-CSR
459483

460484

461-
# 16. Send notifications in cronjob
485+
# 17. Send notifications in cronjob
462486

463487
https://github.com/acmesh-official/acme.sh/wiki/notify
464488

465489

466-
# 17. Under the Hood
490+
# 18. Under the Hood
467491

468492
Speak ACME language using shell, directly to "Let's Encrypt".
469493

470494
TODO:
471495

472496

473-
# 18. Acknowledgments
497+
# 19. Acknowledgments
474498

475499
1. Acme-tiny: https://github.com/diafygi/acme-tiny
476500
2. ACME protocol: https://github.com/ietf-wg-acme/acme
@@ -508,7 +532,7 @@ Support this project with your organization. Your logo will show up here with a
508532

509533

510534

511-
# 19. License & Others
535+
# 20. License & Others
512536

513537
License is GPLv3
514538

@@ -517,7 +541,7 @@ Please Star and Fork me.
517541
[Issues](https://github.com/acmesh-official/acme.sh/issues) and [pull requests](https://github.com/acmesh-official/acme.sh/pulls) are welcome.
518542

519543

520-
# 20. Donate
544+
# 21. Donate
521545
Your donation makes **acme.sh** better:
522546

523547
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)

acme.sh

+104-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ _SCRIPT_="$0"
1717
_SUB_FOLDER_NOTIFY="notify"
1818
_SUB_FOLDER_DNSAPI="dnsapi"
1919
_SUB_FOLDER_DEPLOY="deploy"
20+
_SUB_FOLDER_HTTPAPI="httpapi"
2021

21-
_SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY"
22+
_SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY $_SUB_FOLDER_HTTPAPI"
2223

2324
CA_LETSENCRYPT_V2="https://acme-v02.api.letsencrypt.org/directory"
2425
CA_LETSENCRYPT_V2_TEST="https://acme-staging-v02.api.letsencrypt.org/directory"
@@ -72,6 +73,7 @@ DEFAULT_RENEW=60
7273
NO_VALUE="no"
7374

7475
W_DNS="dns"
76+
W_HTTPAPI="http"
7577
W_ALPN="alpn"
7678
DNS_ALIAS_PREFIX="="
7779

@@ -3396,6 +3398,7 @@ _restoreNginx() {
33963398
_clearup() {
33973399
_stopserver "$serverproc"
33983400
serverproc=""
3401+
_cleanup_http_entries
33993402
_restoreApache
34003403
_restoreNginx
34013404
_clearupdns
@@ -3407,6 +3410,42 @@ _clearup() {
34073410
fi
34083411
}
34093412

3413+
_cleanup_http_entries() {
3414+
if [ -z "$_http_entries" ]; then
3415+
_debug "_cleanup_http_entries: No HTTP entries to clean up"
3416+
return 0
3417+
fi
3418+
_debug "Cleaning up HTTP entries: $_http_entries"
3419+
3420+
entries=$(echo "$_http_entries" | tr "$dvsep" ' ')
3421+
for entry in $entries; do
3422+
d=$(echo "$entry" | cut -d "$sep" -f 1)
3423+
token=$(echo "$entry" | cut -d "$sep" -f 2)
3424+
keyauthorization=$(echo "$entry" | cut -d "$sep" -f 3)
3425+
_httpapi=$(echo "$entry" | cut -d "$sep" -f 4)
3426+
3427+
_debug "Removing HTTP challenge for $d using $_httpapi"
3428+
3429+
h_api="$(_findHook "$d" $_SUB_FOLDER_HTTPAPI "$_httpapi")"
3430+
if [ "$h_api" ]; then
3431+
if ! . "$h_api"; then
3432+
_err "Error loading HTTP API file: $h_api"
3433+
continue
3434+
fi
3435+
3436+
_remove_fn="${_httpapi}_rm"
3437+
if ! _exists "$_remove_fn"; then
3438+
_err "HTTP API file doesn't implement removal function: $_remove_fn"
3439+
continue
3440+
fi
3441+
3442+
if ! "$_remove_fn" "$d" "$token" "$keyauthorization"; then
3443+
_err "Error removing HTTP challenge for domain: $d"
3444+
fi
3445+
fi
3446+
done
3447+
}
3448+
34103449
_clearupdns() {
34113450
_debug "_clearupdns"
34123451
_debug "dns_entries" "$dns_entries"
@@ -4987,6 +5026,56 @@ $_authorizations_map"
49875026
NGINX_RESTORE_VLIST="$d$sep$_realConf$sep$_backup$dvsep$NGINX_RESTORE_VLIST"
49885027
fi
49895028
_sleep 1
5029+
elif _startswith "$_currentRoot" "http_"; then
5030+
_info "Using HTTP API validation for domain: $d"
5031+
_httpapi="$(echo "$_currentRoot" | cut -d "_" -f 2-)"
5032+
h_api="$(_findHook "$d" $_SUB_FOLDER_HTTPAPI "$_currentRoot")"
5033+
_debug h_api "$h_api"
5034+
5035+
if [ "$h_api" ]; then
5036+
_debug "Found domain HTTP API file: $h_api"
5037+
if ! . "$h_api"; then
5038+
_err "Error loading HTTP API file: $h_api"
5039+
_cleanup_http_entries
5040+
_clearup
5041+
_on_issue_err "$_post_hook" "$vlist"
5042+
return 1
5043+
fi
5044+
5045+
_deploy_fn="${_currentRoot}_deploy"
5046+
if ! _exists "$_deploy_fn"; then
5047+
_err "HTTP API file doesn't implement deployment function: $_deploy_fn"
5048+
_cleanup_http_entries
5049+
_clearup
5050+
_on_issue_err "$_post_hook" "$vlist"
5051+
return 1
5052+
fi
5053+
5054+
if ! "$_deploy_fn" "$d" "$token" "$keyauthorization"; then
5055+
_err "Error deploying HTTP challenge for domain: $d"
5056+
_cleanup_http_entries
5057+
_clearup
5058+
_on_issue_err "$_post_hook" "$vlist"
5059+
return 1
5060+
fi
5061+
5062+
_http_entries="${_http_entries}${d}${sep}${token}${sep}${keyauthorization}${sep}${_currentRoot}${dvsep}"
5063+
else
5064+
# Fall back to normal webroot challenge if no hook is found
5065+
_info "No HTTP API hook found for $_currentRoot, falling back to normal validation"
5066+
if [ "$_currentRoot" = "apache" ]; then
5067+
wellknown_path="$ACME_DIR"
5068+
else
5069+
wellknown_path="$_currentRoot/.well-known/acme-challenge"
5070+
if [ ! -d "$_currentRoot/.well-known" ]; then
5071+
removelevel='1'
5072+
elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ]; then
5073+
removelevel='2'
5074+
else
5075+
removelevel='3'
5076+
fi
5077+
fi
5078+
fi
49905079
else
49915080
if [ "$_currentRoot" = "apache" ]; then
49925081
wellknown_path="$ACME_DIR"
@@ -7073,6 +7162,7 @@ Parameters:
70737162
70747163
--password <password> Add a password to exported pfx file. Use with --to-pkcs12.
70757164
7165+
--http-api <provider> Use HTTP API for challenge validation
70767166
70777167
"
70787168
}
@@ -7351,6 +7441,7 @@ _process() {
73517441
_preferred_chain=""
73527442
_valid_from=""
73537443
_valid_to=""
7444+
_http_api=""
73547445
while [ ${#} -gt 0 ]; do
73557446
case "${1}" in
73567447

@@ -7873,6 +7964,18 @@ _process() {
78737964
_preferred_chain="$2"
78747965
shift
78757966
;;
7967+
--http-api)
7968+
wvalue="$W_HTTPAPI"
7969+
if [ "$2" ] && ! _startswith "$2" "-"; then
7970+
wvalue="$2"
7971+
shift
7972+
fi
7973+
if [ -z "$_webroot" ]; then
7974+
_webroot="$wvalue"
7975+
else
7976+
_webroot="$_webroot,$wvalue"
7977+
fi
7978+
;;
78767979
*)
78777980
_err "Unknown parameter: $1"
78787981
return 1

0 commit comments

Comments
 (0)