Stateless Mode
Configure your webserver to respond statelessly to challenges for a given account key. This requires nothing more than a one-time web server configuration change and no "moving parts".
-
First get your account key thumbprint:
root@ed:~# acme.sh --register-account [Mon Feb 6 21:40:18 CST 2017] Registering account [Mon Feb 6 21:40:19 CST 2017] Already registered [Mon Feb 6 21:40:21 CST 2017] Update success. [Mon Feb 6 21:40:21 CST 2017] ACCOUNT_THUMBPRINT='6fXAG9VyG0IahirPEU2ZerUtItW2DHzDzD9wZaEKpqd'Remember the thumbprint in the last line:
6fXAG9VyG0IahirPEU2ZerUtItW2DHzDzD9wZaEKpqd -
Configure the web server to return the account key thumbprint:
NGINX
Add something similar to your
nginx.conf:http { ... server { ... location ~ ^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)$ { default_type text/plain; return 200 "$1.6fXAG9VyG0IahirPEU2ZerUtItW2DHzDzD9wZaEKpqd"; } ... } }CADDY
Add something similar to your
Caddyfile:example.com { @achallenge { path_regexp ch ^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)$ } respond @achallenge "{re.ch.1}.6fXAG9VyG0IahirPEU2ZerUtItW2DHzDzD9wZaEKpqd"APACHE
Tested on Apache 2.4.62
Add something similar to your
httpd.conf:... <VirtualHost *:80> ... <LocationMatch "/.well-known/acme-challenge/(?<challenge>[-_a-zA-Z0-9]+)"> RewriteEngine On RewriteRule "^([-_a-zA-Z0-9]+)$" "$1" [E=challenge:$1] ErrorDocument 200 "%{ENV:MATCH_CHALLENGE}.6fXAG9VyG0IahirPEU2ZerUtItW2DHzDzD9wZaEKpqd" RewriteRule ^ - [L,R=200] </LocationMatch> ... </VirtualHost> ...HAPROXY
Add the http-request return rule to your configuration:
global setenv ACCOUNT_THUMBPRINT '6fXAG9VyG0IahirPEU2ZerUtItW2DHzDzD9wZaEKpqd' log stderr local0 stats socket /var/run/haproxy.sock level admin mode 0666 frontend web log global option httplog mode http bind :80 bind :443 ssl crt /etc/haproxy/certs/ http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].${ACCOUNT_THUMBPRINT}\n" if { path_reg '^/.well-known/acme-challenge/[-_a-zA-Z0-9]+$' }IIS
The solution for the IIS (Microsoft) is a bit more difficult as it does not support returning a custom body directly in a web.config. So we need two parts, first the
web.configfile in the .well-known/acme-challenge/ folder:<?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <httpRedirect enabled="false" /> <validation validateIntegratedModeConfiguration="false" /> <staticContent> <clear /> <mimeMap fileExtension="." mimeType="text/json" /> <mimeMap fileExtension=".*" mimeType="text/json" /> </staticContent> <rewrite> <rules> <rule name="ACME Stateless Mode" stopProcessing="true"> <match url="^([A-Za-z0-9_-]+)$" /> <action type="Rewrite" url="acme-challenge.ashx?token={R:1}" appendQueryString="false" /> </rule> </rules> </rewrite> </system.webServer> <system.web> <authorization> <allow users="*" /> </authorization> </system.web> </configuration>The config above also includes some useful configuration entries for IIS when using it for the ACME challenge. As second part we use a ASP.NET handler to return the correct content, store this as
acme-challenge.ashxin the same folder, do not forget to adjust the thumbprint:<%@ WebHandler Language="C#" Class="AcmeChallengeHandler" %> using System; using System.Text.RegularExpressions; using System.Web; public class AcmeChallengeHandler : IHttpHandler { // Your ACME account thumbprint (e.g. from `acme.sh --register-account`). private const string AccountThumbprint = "YOUR_THUMBPRINT_HERE"; // ACME tokens are base64url: letters, digits, '-' and '_'. private static readonly Regex TokenPattern = new Regex("^[A-Za-z0-9_-]{1,256}$", RegexOptions.Compiled); public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { HttpResponse response = context.Response; response.Clear(); response.ContentType = "text/plain"; response.Cache.SetCacheability(HttpCacheability.NoCache); string token = context.Request.QueryString["token"] ?? string.Empty; if (!TokenPattern.IsMatch(token)) { response.StatusCode = 404; response.Write("Not found"); return; } response.StatusCode = 200; response.Write(token + "." + AccountThumbprint); } } -
Ok, you can issue cert now.
acme.sh --issue -d example.com --stateless