1---
2title: Renewal & revocation
3description: Schedule renewal, understand replacement and deletion, and protect certificate and account keys.
4---
5
6An `ACME.Certificate` is checked when Alchemy plans a deployment. It has no
7background timer. Keeping the stack deployed is not enough to keep its
8certificates renewed.
9
10## Choose a renewal window
11
12In the certificate from [Getting started](/acme/getting-started):
13
14```diff lang="typescript"
15 const certificate = yield* ACME.Certificate("Site", {
16 account,
17 identifiers: ["example.com"],
18 solver: Cloudflare.DNS.AcmeSolver({
19 zoneId: Config.String("CLOUDFLARE_ZONE_ID"),
20 }),
21+ renewBefore: "30 days",
22 });
23```
24
25Thirty days is the default. When less than this remains before `notAfter`, a
26deployment issues a new certificate with a fresh private key and updates the
27resource outputs. Choose a window shorter than the CA's certificate lifetime;
28a longer window can cause issuance on every deployment.
29
30## Schedule deployments
31
32```sh
33alchemy deploy --stage prod --profile prod --yes
34```
35
36Run the same deployment regularly from your existing scheduler or CI runner.
37Daily is a reasonable starting point for a 30-day renewal window. The runner
38must use the same stack name, stage, protected state backend, source revision,
39and necessary credentials as the production deployment. `--yes` approves the
40plan, so review source changes separately and serialize deployments to that
41stack. See [CI setup](/environments/ci) for credential configuration.
42
43## Monitor expiry independently
44
45Return `certificate.notAfter` from the stack and feed it into your monitoring.
46Also inspect the certificate actually served by your TLS endpoint: updating
47Alchemy's state does not prove that an external service loaded the replacement.
48Alert early enough to investigate DNS failures, rejected orders, or unavailable
49credentials before the old certificate expires.
50
51## Understand which changes issue again
52
53| Change | Result |
54| --- | --- |
55| Certificate is inside `renewBefore` | Update: issue a new certificate and key |
56| Identifier set changes | Update: issue again |
57| Certificate `keyAlgorithm` changes | Update: issue again |
58| `preferredChain` changes | Update: issue again |
59| Issuing account URL changes | Replace the certificate resource |
60| Solver or propagation settings alone change | Keep the valid certificate; use new settings on later issuance |
61| `revokeOnDelete` changes | Update deletion policy without issuing again |
62
63An ordinary renewal updates the stored certificate; it does not automatically
64revoke the previous one. Retain any old material securely if your operational
65process needs explicit revocation after cutover.
66
67## Revoke on resource deletion
68
69```diff lang="typescript"
70 const certificate = yield* ACME.Certificate("Site", {
71 account,
72 identifiers: ["example.com"],
73 solver: Cloudflare.DNS.AcmeSolver({
74 zoneId: Config.String("CLOUDFLARE_ZONE_ID"),
75 }),
76+ revokeOnDelete: true,
77 });
78```
79
80This opts into CA revocation when that certificate resource is deleted, including
81deletion of an old resource generation during replacement. It does not revoke
82old certificates on every in-place renewal. Revocation uses the certificate's
83own private key, so deleting an old certificate can still work after its account
84has been deactivated.
85
86## Destroy a stack deliberately
87
88```sh
89alchemy destroy --stage dev
90```
91
92With the default `revokeOnDelete: false`, deletion forgets certificate state but
93leaves the certificate valid at the CA. Account deletion deactivates the ACME
94account; deactivation is distinct from revoking its issued certificates. Removing
95a certificate from a TLS consumer is another separate operation.
96
97:::caution
98Save any material needed for later revocation before destroying state. Once the
99key is gone, you cannot rely on this stack to revoke the certificate. If the
100certificate is still serving traffic, replace it at the consumer before revoking
101it.
102:::
103
104## Protect account and certificate keys
105
106The account's `privateKey` is a redacted private JWK used for ACME requests. The
107certificate's `privateKey` is a redacted PKCS#8 PEM used by the TLS server. They
108are separate keys with separate purposes.
109
110Restrict state access to trusted deployment identities, use encryption at rest
111where your backend supports it, protect backups, and exclude local state from
112source control. `Redacted` is a logging safeguard, not encryption. Avoid returning
113keys as top-level stack outputs or unwrapping them for diagnostic logging.
114
115The certificate resource's read operation returns persisted attributes; it does
116not query the CA for out-of-band revocation. Expiry checks alone are therefore
117not a certificate-status monitoring system.
118
119## Renew runtime-issued certificates
120
121For certificates issued through `IssueCertificate`, your application must store
122the chain, key, expiry, and enough account/domain metadata to manage the result.
123Schedule a new `issue` call before expiry, install the new material at the
124consumer, verify it is serving, and only then retire the previous certificate.
125
126Serialize issuance per identifier set, persist jobs durably, and honor CA retry
127hints. An in-memory Worker variable is not durable storage or a renewal schedule.
128Destroying the account stack does not discover or clean up runtime-issued
129certificates for you.
130
131## Next steps
132
133- [Using certificates](/acme/using-certificates) — connect renewal outputs to a TLS consumer.
134- [Runtime issuance](/acme/runtime) — issue and revoke through an application binding.
135- [Troubleshooting](/acme/troubleshooting) — investigate a failed renewal.