commit 24a2913c4e1cb31a5cff52047beae146959d50b0
parent d555cea0cda80640296647e1a15547c11217652a
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date: Tue, 1 Sep 2026 02:49:21 +0200
ACME examples: added readme
Diffstat:
2 files changed, 147 insertions(+), 0 deletions(-)
diff --git a/src/examples2/acme/Makefile.am b/src/examples2/acme/Makefile.am
@@ -24,3 +24,6 @@ noinst_PROGRAMS = \
acme_http_01_redirect \
acme_http_01_files \
acme_http_01_token
+
+EXTRA_DIST = \
+ README.md
diff --git a/src/examples2/acme/README.md b/src/examples2/acme/README.md
@@ -0,0 +1,144 @@
+# Using the ACME examples
+
+ACME is a protocol for obtaining TLS certificates automatically. Before
+issuing a certificate, the ACME service checks that the domain is really
+yours: it requests a specific resource from that domain over plain HTTP. The
+examples in this directory are minimal servers that answer such requests.
+
+There is no shortage of helper tools that take much of the fiddly work out of
+using ACME. This guide uses [`acme.sh`](https://github.com/acmesh-official/acme.sh),
+which is distributed under the excellent GNU General Public License version 3
+(GPLv3).
+
+For the setup described here, `acme.sh` can use either `wget` or `curl` to talk
+to ACME servers, and the examples in this directory to answer their HTTP-01
+challenge requests. Beyond that, it needs only OpenSSL for the cryptographic
+work involved in obtaining certificates automatically, plus the usual
+command-line utilities. This small set of requirements makes the combination
+particularly handy for compact and embedded systems.
+
+## Getting the first certificate
+
+The simplest way to create a certificate is to run the commands below. Replace
+the example email address and domain name with your own values.
+
+The commands use the server selected in the `acme.sh` configuration. Testing
+with a staging server first is strongly recommended, as its certificates are
+deliberately not publicly trusted. Add `--staging` to both `acme.sh` commands
+below to use the staging server. Another service can be selected in the
+`acme.sh` configuration or with its `--server` option.
+
+Register an ACME account first:
+
+```sh
+acme.sh --register-account \
+ --email admin@example.com
+```
+
+Registration is needed only once (for each ACME server). Prepare a temporary
+webroot, then start the MHD example and leave it running:
+
+```sh
+mkdir -p /tmp/acme-check
+./acme_http_01_files --webroot /tmp/acme-check 80
+```
+
+The last argument is the local listening port. ACME HTTP-01 requests always
+arrive on public port 80; if that port is forwarded to another local port, give
+the forwarded-to port here instead.
+
+In another terminal, ask `acme.sh` to issue the certificate:
+
+```sh
+acme.sh --issue \
+ --domain example.com \
+ --webroot /tmp/acme-check
+```
+
+The example is needed only while the validation is running. Once `acme.sh`
+has finished, stop the example by pressing ENTER in its terminal; all the
+examples in this directory are stopped this way.
+
+With the current `acme.sh` defaults, the files needed by MHD are
+`~/.acme.sh/example.com_ecc/fullchain.cer` and
+`~/.acme.sh/example.com_ecc/example.com.key`. The former already contains the
+server certificate followed by its signing chain. Load the contents of both
+files and pass them to MHD as the certificate chain and private key,
+respectively.
+
+To renew the certificate, start the example with the same webroot again and
+run:
+
+```sh
+acme.sh --renew --domain example.com
+```
+
+`acme.sh` remembers the webroot and ACME server used for issuance. If renewal
+is not due yet, it simply skips the operation; use `--force` only when an
+immediate renewal is really wanted.
+
+The example does not have to run as a separate process. Its code can be
+integrated directly into an application that keeps its main MHD daemon on a TLS
+port. When certificate renewal is due, the application can start a second MHD
+daemon on port 80 solely to answer ACME HTTP-01 challenges, then stop it after
+the validation has finished.
+
+If this simple file-based setup is all you need, you can stop reading here.
+
+## Getting a certificate with an account thumbprint
+
+> **Warning:** This method is not recommended. While the server is running,
+> it will confirm every syntactically valid HTTP-01 challenge request that
+> reaches it for the selected ACME account. See RFC 8555, section 8.3.
+
+The challenge files can be avoided by building each response from the request
+token and the thumbprint of the ACME account key. The following single command
+registers the account if needed, extracts its thumbprint and immediately starts
+the MHD example server in `--naive` mode:
+
+```sh
+./acme_http_01_token --naive 80 "$(acme.sh --register-account \
+ --email admin@example.com 2>&1 | \
+ sed -n "s/.*ACCOUNT_THUMBPRINT='\([^']*\)'.*/\1/p")"
+```
+
+The extraction is possible because `acme.sh` reports the thumbprint in a
+fixed form, as a single line with the value in quotes:
+
+```text
+[Mon Sep 1 02:32:00 CEST 2026] ACCOUNT_THUMBPRINT='pkZoLgVnRb3rWG1mAaKQm3ZDb6xU_c0dOtd_uBaC5Ns'
+```
+
+The `sed` expression above takes the value from between the quotes, so the
+thumbprint never has to be copied by hand.
+
+The same command can be run again whenever the server is needed. For an
+existing account, no new registration is performed: `acme.sh` simply prints
+its current thumbprint. As above, add `--staging` to the `acme.sh` command
+when testing on the staging server.
+
+In another terminal, request the certificate in stateless mode, using the same
+ACME server and account configuration:
+
+```sh
+acme.sh --issue --stateless --domain example.com
+```
+
+Add `--staging` here as well when staging was selected for the account. Once
+the validation has finished, press ENTER to stop the example. The certificate
+and key are stored in the same locations described above.
+
+For renewal, start the example with the same account thumbprint again and run:
+
+```sh
+acme.sh --renew --domain example.com
+```
+
+`acme.sh` remembers both stateless mode and the ACME server used for issuance,
+so neither needs to be repeated in the renewal command. Stop the example as
+soon as validation has finished.
+
+This example can be integrated into an application as well. The application
+keeps the account thumbprint, starts a second MHD daemon on port 80 when the
+renewal is due and stops it once the validation has finished. No files are
+involved, so nothing has to be shared between the processes.