update wiki

neil
2026-05-01 15:12:07 +02:00
parent 3484183edf
commit 3eb7404539
8 changed files with 298 additions and 11 deletions

86
ARI.md Normal file

@@ -0,0 +1,86 @@
acme.sh implements **ACME Renewal Information** ([RFC 9773](https://www.rfc-editor.org/rfc/rfc9773.html)) automatically. **No flag, no opt-in, no configuration needed.**
If your CA exposes a `renewalInfo` endpoint in its ACME directory (Let's Encrypt, ZeroSSL, Sectigo, SSL.com, …), acme.sh will use it. If the CA does not, acme.sh falls back to the classic 30-day fixed-interval rule — behavior is identical to before.
## What it does
| What | When | Why |
|------|------|-----|
| 🔍 **Polls `suggestedWindow`** | Every cron run, before deciding to skip | Lets the CA shift renewal forward in case of an incident (key compromise, mass revocation) |
| 🎯 **Picks a random renewal time** inside the window | Right after a successful issuance/renewal | Disperses renewals across the network so all clients don't hit the CA at the same instant |
| 🔗 **Sends `replaces=<certID>`** in newOrder | On `--renew` | Lets the CA correlate the new order with the certificate it supersedes (RFC 9773 §5) |
| ↩️ **Retries without `replaces`** | If the CA returns `alreadyReplaced` or an ARI validation error | Robust against edge cases (switching CAs, retired issuers, parallel renewal) |
## When does the cert renew?
acme.sh renews when **any one** of these is true:
1. `--force` is given
2. The CA's **ARI `suggestedWindow.start` has passed** (so the CA is asking you to renew now)
3. The cached `Le_NextRenewTime` has passed (the classic 30-day fallback, also used when no ARI)
This means a CA can effectively command an early renewal across the entire `acme.sh` user base by shrinking the suggested window — useful for emergency incident response.
## Why this matters
Short-lived certificates (Apple's 47-day proposal, Let's Encrypt's shortlived profile, etc.) are coming. With shorter lifetimes, fixed-interval renewal becomes brittle:
- A 7-day cert with a 30-day fixed renewal interval would always be expired
- All clients renewing at the same offset would hammer the CA
- Emergency revocations need a way to push the renewal time forward
ARI solves all three. The CA gets full control of *when* to renew; clients just follow its hints.
## How to inspect
The chosen next-renewal time is saved in the domain conf as `Le_NextRenewTimeStr`:
```sh
acme.sh --info -d example.com
# Look for: Le_NextRenewTimeStr=...
```
To see the live ARI window the CA is currently advertising, run with `--debug 2`:
```sh
acme.sh --renew -d example.com --debug 2 2>&1 | grep -i 'ARI suggestedWindow'
```
Example output:
```
[INFO] ARI suggestedWindow: 2026-05-06T19:48:34Z to 2026-05-08T14:59:23Z
[INFO] Next renewal time picked from ARI window: 2026-05-07T16:57:49Z
```
## Internals
- **certID** for ARI requests is computed per RFC 9773 §4.1 as `base64url(AKI) + "." + base64url(Serial)` of the existing certificate.
- **Window pick** is `start + (current_epoch % window_size)`. This is intentionally pseudo-random across clients (different cert issuance moments → different offsets) without needing crypto-grade randomness, and it is the same simple "use current time as entropy" pattern acme.sh already uses for cron randomization.
- **Failure handling**: any failure mode (ARI 404, network error, malformed response, CA does not support ARI) cleanly falls back to the original fixed-interval `Le_NextRenewTime` logic. ARI is a strict enhancement.
## Relationship to other features
- **Compatible with all validation modes**: webroot, standalone, alpn, DNS API, DNS manual, [DNS persist](https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode). ARI only changes *when* renewals happen, not *how* they validate.
- **Compatible with `--valid-to` / `--valid-from`** ([Validity](https://github.com/acmesh-official/acme.sh/wiki/Validity)): when an explicit notAfter is set, acme.sh respects the user-provided deadline and does not let ARI override it.
- **Compatible with `--cert-profile`** ([Profile selection](https://github.com/acmesh-official/acme.sh/wiki/Profile-selection)): independent.
## CAs known to support ARI
- ✅ Let's Encrypt
- ✅ ZeroSSL (when ACME server returns `renewalInfo`)
- Check your CA's directory — if it has a `"renewalInfo"` field, ARI is on.
```sh
curl -s https://acme-v02.api.letsencrypt.org/directory | grep renewalInfo
```
## Spec reference
Full normative reference: [RFC 9773 — Automated Certificate Management Environment (ACME) Renewal Information (ARI) Extension](https://www.rfc-editor.org/rfc/rfc9773.html)
Key sections:
- §4.1 — certID computation
- §4.2 — `suggestedWindow` shape
- §4.3 — polling and `Retry-After`
- §5 — newOrder `replaces` field
- §7.4 — `alreadyReplaced` error code

@@ -1,9 +1,10 @@
Warning: DNS manual mode can not renew automatically.
If your domain provider offers an DNS API, it's highly recommended to use DNS API mode instead. With the DNS API mode, you can automate the renewals.
If your domain provider offers an DNS API, it's highly recommended to use DNS API mode instead. With the DNS API mode, you can automate the renewals.
If your domain provider does **not** offer an API but you can edit your zone, **the recommended mode for unattended renewals is now [DNS persist mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode)**: you publish a single long-lived TXT record once, then renewals run automatically forever — no per-renewal DNS edit. DNS persist follows [draft-ietf-acme-dns-persist-01](https://datatracker.ietf.org/doc/draft-ietf-acme-dns-persist/).
If your domain provider does **not** offer an API where you can add/edit TXT records of your domain, it is recommended to use [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode) instead. Or change the dns servers of your domain to anyone that support DNS api.
If neither API access nor DNS persist is available, you may also use [DNS alias mode](https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode), or change the DNS servers of your domain to one that supports DNS API.
DNS manual mode **should** be used for testing. If you do use it for your production server, remember to renew your certificate within 90 days. [Please, make sure you understand DNS manual mode](https://github.com/Neilpang/acme.sh/issues/1029).

111
DNS-persist-mode.md Normal file

@@ -0,0 +1,111 @@
DNS persist mode lets you publish a **single, long-lived TXT record once** in your zone and then issue / renew certificates **forever without further DNS edits** — including unattended cron renewals.
It implements [draft-ietf-acme-dns-persist-01](https://datatracker.ietf.org/doc/draft-ietf-acme-dns-persist/), an IETF draft that defines a persistent DNS authorization record at `_validation-persist.<your-domain>`.
## Why use it
DNS validation has historically forced a tradeoff:
| Mode | Auto-renewal | Needs API access |
|------|--------------|------------------|
| [DNS API mode](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) | ✅ Yes | ✅ Required |
| [DNS manual mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-manual-mode) | ❌ No (manual every renewal) | ❌ Not needed |
| **DNS persist mode** | ✅ **Yes** | ❌ **Not needed** |
If your DNS provider does not offer an API, but you can edit your zone once, **DNS persist is the right mode**. Renewals are fully automatic afterwards.
## Step 1: Print the TXT record value
```sh
acme.sh --make-dns-persist-value -d example.com
```
You'll get an output like:
```
TXT persist domain:_validation-persist.example.com
TXT persist value :"letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/123456789"
```
The TXT value is human-readable text in the syntax of [RFC 8659 §4.2](https://www.rfc-editor.org/rfc/rfc8659.html#name-issue-property):
```
issuer-domain-name; accounturi=<your-account-uri>[; policy=wildcard]
```
If the CA's directory advertises multiple `caaIdentities` (e.g. ZeroSSL lists `sectigo.com`, `trust-provider.com`, etc.), one TXT record per identity is printed — **you only need to add ANY ONE of them**.
### Optional flags for `--make-dns-persist-value`
| Flag | Description |
|------|-------------|
| `--server <ca>` | Pick the CA. The account is registered automatically if you have not used this CA before. Default is your configured default CA. |
| `--dns-persist-wildcard` | Adds `policy=wildcard` to the record so it also authorizes wildcard / subdomain certs. |
| `--dns-persist-ca-name <name>` | Use a specific CA identity domain (e.g. `ssl.com`). If omitted, identities are read from the ACME directory's `caaIdentities` field. |
| `--dns-persist-days <N>` | Adds a `persistUntil` field to the record so it self-expires N days from now. After that timestamp, the CA will refuse new validations against this record. Useful if you want a time-bounded authorization. Omit for a record with no expiry. |
Examples:
```sh
# Let's Encrypt
acme.sh --make-dns-persist-value -d example.com --server letsencrypt
# Wildcard policy (also authorizes *.example.com)
acme.sh --make-dns-persist-value -d example.com --dns-persist-wildcard
# Force a specific issuer name
acme.sh --make-dns-persist-value -d example.com --dns-persist-ca-name "ssl.com"
# Self-expire the authorization after 365 days
acme.sh --make-dns-persist-value -d example.com --dns-persist-days 365
```
## Step 2: Add the TXT record at your DNS provider
Use whatever interface your DNS provider gives you to add the TXT record. The name is `_validation-persist.<your-domain>` and the value is the quoted string from the previous step.
Wait for DNS propagation (usually a few minutes).
## Step 3: Issue the certificate
```sh
acme.sh --issue -d example.com --dns-persist
```
The CA reads your persistent TXT record directly — **no challenge token is provisioned during issuance**. This is the key difference vs. dns-01 / DNS API modes.
## Renewal
Cron will renew automatically — the same TXT record is reused forever. Combined with [ARI](https://github.com/acmesh-official/acme.sh/wiki/ARI), the CA also picks the renewal time for you, so the entire lifecycle is unattended.
```sh
# Manual renewal also works:
acme.sh --renew -d example.com
```
## Trust model & security notes
The persistent TXT record contains your **ACME account URI**. This means:
- Only the holder of the corresponding ACME account key (i.e. you, on this machine) can issue certs for your domain through this record.
- Anyone reading your DNS sees your account URI. The account URI itself is not a secret — it identifies the account, but you also need the matching private key to use it. No issue.
- If you lose your ACME account key (for example, you reinstall and don't restore `~/.acme.sh/`), the TXT record becomes useless. You'll need to print and re-publish a new one with the new account.
- If you want to revoke this authorization, simply delete the TXT record.
### Wildcard policy
By default the record only authorizes the **exact** FQDN. Add `policy=wildcard` (via `--dns-persist-wildcard`) to additionally authorize:
- The base domain
- `*.<base domain>` wildcards
- Specific subdomains under it
## Compatibility
DNS persist is an IETF draft. Check that your CA implements it before relying on it.
## Related
- [DNS manual mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-manual-mode) — if you only want a one-off cert
- [DNS API providers](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) — if your DNS provider has an API
- [ARI auto-renewal](https://github.com/acmesh-official/acme.sh/wiki/ARI) — RFC 9773 renewal info

@@ -9,6 +9,11 @@ https://wiki.acme.sh
Here is the wiki page for acme.sh
## What's new
- 📡 **[ARI auto-renewal (RFC 9773)](https://github.com/acmesh-official/acme.sh/wiki/ARI)** — acme.sh now follows the CA's `renewalInfo` endpoint automatically. No flag, no opt-in. Lets the CA shift renewals forward in case of an incident.
- 📌 **[DNS persist mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode)** — publish one TXT record once, renew forever without DNS API and without per-renewal manual edits. Implements draft-ietf-acme-dns-persist-01.
## 1. How to install
https://github.com/acmesh-official/acme.sh/wiki/How-to-install
@@ -26,7 +31,7 @@ After installation,
```
/root/.acme.sh/acme.sh --issue --standalone -d <DOMAIN>
```
After issuing, the cert will be automatically renewed every 60 days.
After issuing, the cert will be automatically renewed (every ~30 days, or earlier if the CA's [ARI](https://github.com/acmesh-official/acme.sh/wiki/ARI) endpoint advises so).
3) Install the cert to Proxmox:

@@ -60,7 +60,23 @@ See: https://github.com/acmesh-official/acme.sh/wiki/DNS-manual-mode
See: https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode
#### 7) Apache mode:
#### 7) DNS persist mode:
If your DNS provider does **not** offer an API but you can edit your zone once, DNS persist mode lets you publish a single long-lived TXT record and renew automatically forever — no per-renewal DNS edits.
```sh
# Step 1: print the TXT record value
acme.sh --make-dns-persist-value -d example.com
# Step 2: add the printed _validation-persist.example.com TXT record at your DNS provider
# Step 3: issue
acme.sh --issue -d example.com --dns-persist
```
See: https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode
#### 8) Apache mode:
If your website is running apache server, acme.sh can use apache server to issue cert. And acme.sh will restore your apache conf after the cert is issued, don't worry.
@@ -68,7 +84,7 @@ If your website is running apache server, acme.sh can use apache server to issue
acme.sh --issue -d example.com --apache
```
#### 8) Nginx mode:
#### 9) Nginx mode:
If your website is running nginx server, acme.sh can use nginx server to issue cert. And acme.sh will restore your nginx conf after the cert is issued, don't worry.

@@ -23,6 +23,9 @@ Commands:
--update-account Update account info.
--register-account Register account key.
--deactivate-account Deactivate the account.
--make-dns-persist-value Print the DNS TXT record(s) to enable persistent DNS validation
(draft-ietf-acme-dns-persist-01). Use with -d <domain>.
See: https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode
--create-account-key Create an account private key, professional use.
--install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
--uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
@@ -60,6 +63,25 @@ Parameters:
--dns [dns_hook] Use dns manual mode or dns api. Defaults to manual mode when argument is omitted.
See: https://github.com/acmesh-official/acme.sh/wiki/dnsapi
--dns-persist Use dns-persist-01 validation (draft-ietf-acme-dns-persist-01).
Requires the persistent _validation-persist TXT record to already exist.
Use '--make-dns-persist-value' to print the value to add.
See: https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode
--dns-persist-wildcard Used with '--make-dns-persist-value'. Adds 'policy=wildcard' to the
generated TXT record so the issuer is also authorized for wildcards
and subdomains.
--dns-persist-ca-name <name> Used with '--make-dns-persist-value'. Use the given CA identity domain
(e.g. 'ssl.com') as the issuer-domain-name in the TXT record. If
omitted, identities are read from the ACME directory's 'caaIdentities'
field and one record is printed per identity.
--dns-persist-days <N> Used with '--make-dns-persist-value'. Add a 'persistUntil' field to
the TXT record so the record self-expires N days from now (the CA
will refuse new validations against the record after that time).
If omitted, the record has no expiry.
--dnssleep <seconds> The time in seconds to wait for all the txt records to propagate in dns api mode.
It's not necessary to use this by default, acme.sh polls dns status by DOH automatically.
-k, --keylength <bits> Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521.
@@ -89,7 +111,7 @@ Parameters:
--useragent <string> Specifies the user agent string. it will be saved for future use too.
-m, --email <email> Specifies the account email, only valid for the '--install' and '--update-account' command.
--accountkey <file> Specifies the account key path, only valid for the '--install' command.
--days <ndays> Specifies the days to renew the cert when using '--issue' command. The default value is 60 days.
--days <ndays> Specifies the days to renew the cert when using '--issue' command. The default value is 30 days. Note: when the CA supports ARI (RFC 9773), the actual renewal time is picked from the CA's suggestedWindow and this fixed-day fallback is overridden. See the wiki page on ARI.
--httpport <port> Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
--tlsport <port> Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
--local-address <ip> Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
@@ -136,4 +158,10 @@ Parameters:
```
```
## Note on automatic renewal timing
If your CA exposes the ACME Renewal Information (ARI, RFC 9773) endpoint in its directory, acme.sh automatically uses the CA's `suggestedWindow` to schedule renewals — no flag is required. The cert is renewed when **any one** of the following becomes true: `--force` is given, the ARI window has started, or the cached `Le_NextRenewTime` has passed.
See: https://github.com/acmesh-official/acme.sh/wiki/ARI

@@ -47,7 +47,7 @@ Please be careful about the format, there are only `+*d` (for days) and `+*h` (
1. `--valid-to +20d`(the cert will be renewed every 19 days). If the lifetime is longer than one day, it will renew at one day before.
2. `--valid-to +11h`(the cert will be renewed every 10 hours). If the lifttime is less than 24 hourst, it will renew at one hour before.
## Of course, if you don't use `--valid-to` parameter at all, the cert will be renewed every `60 days` as before.
## Of course, if you don't use `--valid-to` parameter at all, the cert will be renewed every `30 days` (or earlier if the CA's [ARI](https://github.com/acmesh-official/acme.sh/wiki/ARI) suggestedWindow says so).

@@ -118,7 +118,7 @@ acme.sh --set-default-ca --server letsencrypt
这需要你手动在域名上添加一条 TXT 解析记录,验证域名所有权。
注意如果使用手动验证acme.sh 将无法自动更新证书,每次都需要手动添加解析来验证域名所有权。**如果有自动更新证书的需求,请使用自动验证DNS API。**
注意如果使用手动验证acme.sh 将无法自动更新证书,每次都需要手动添加解析来验证域名所有权。**如果有自动更新证书的需求,但 DNS 服务商没有 API推荐使用下面的「DNS Persist 模式」。**
```shell
acme.sh --issue --dns -d example.com -d www.example.com -d cp.example.com
@@ -134,6 +134,35 @@ acme.sh --renew -d mydomain.com
注意这里现在用的是 `--renew` 参数
### DNS Persist 模式(持久化 DNS 验证,无 API 也能自动续签)
如果你的 DNS 服务商**没有 API**但你能编辑一次解析记录DNS Persist 模式让你只添加一条**长期有效的** TXT 记录,之后续签全程自动,**不再需要每次改 DNS**。
实现的是 IETF 草案 [draft-ietf-acme-dns-persist-01](https://datatracker.ietf.org/doc/draft-ietf-acme-dns-persist/)。
```shell
# 第 1 步:打印需要添加的 TXT 记录值
acme.sh --make-dns-persist-value -d example.com
# 第 2 步:在你的 DNS 服务商面板里添加打印出来的 _validation-persist.example.com TXT 记录,等待解析生效
# 第 3 步:签发
acme.sh --issue -d example.com --dns-persist
```
可选参数(用在第 1 步):
| 参数 | 作用 |
|------|------|
| `--server <ca>` | 指定 CA(默认是你已配置的默认 CA)。如果还没在该 CA 注册过账户,会自动注册。|
| `--dns-persist-wildcard` | 给记录加 `policy=wildcard`,同时授权通配符 / 子域证书。|
| `--dns-persist-ca-name <name>` | 指定特定的 CA 标识域名(例如 `ssl.com`)。省略时,从 ACME directory 的 `caaIdentities` 字段读取,每个标识各打印一条记录(任选其一添加即可)。|
| `--dns-persist-days <N>` | 给记录加 `persistUntil` 字段,使记录在 N 天后自动失效(CA 之后不再接受针对该记录的新验证)。省略则永不过期。|
之后 cron 会自动续签,这条 TXT 记录会被反复复用,无需再动 DNS。
详见: https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode
### 自动验证DNS API
DNS 方式的真正强大之处在于可以使用域名解析商提供的 API 自动添加 TXT 记录,且在完成验证后删除对应的记录。
@@ -223,14 +252,25 @@ Le_RealFullChainPath=/etc/acme/example.com/chain.pem
# 5. 更新证书
目前证书每 30 天自动更新你无需任何操作。
证书自动更新,你无需任何操作。默认每 30 天自动更新一次,**或者更早**——如果 CA 通过 ACME Renewal Information(ARI,[RFC 9773](https://www.rfc-editor.org/rfc/rfc9773.html))告知应当提前续签时,acme.sh 会自动遵守。
但是你也可以强制续签证书:
ARI 完全自动,**没有任何参数,无需开启**。如果 CA 的 directory 里没有 `renewalInfo` 端点,自动退回经典的 30 天规则,行为不变。
详见: https://github.com/acmesh-official/acme.sh/wiki/ARI
如果想立即强制续签,可以:
```shell
acme.sh --renew -d example.com --force
```
查看下次续签时间:
```shell
acme.sh --info -d example.com
# 看 Le_NextRenewTimeStr 字段
```
# 6. 关于修改 `reloadcmd`
目前修改 `reloadcmd` 没有专门的命令,可以通过重新安装证书来实现修改 `reloadcmd` 的目的。