This blog post describes my Let’s Encrypt solution which uses acme.sh and dns-01 challenges to obtain SSL certificates. If you are using HTTP challenges, this post might still be useful, but your configuration will differ slightly.
Let’s Encrypt is a certificate authority which has become wildly popular since it was launched in April 2016 (just a short 14 months ago). Why so popular? It provides a secure way to offer free SSL certificates. The goal: make it easy to automate the provisioning of SSL certificates for websites.
What is ACME? Automated Certificate Management Environment is a “communications protocol for automating interactions between certificate authorities and their users’ web servers, allowing the automated deployment of public key infrastructure at very low cost”.
I have been working on this project ever since I read Peter Wemm’s blog post about how the FreeBSD project uses Let’s Encrypt. I liked the centralized approach to renewing all of your certs from one jail, then distributing them out to where they are used.
Why do I like that?
- It reduces your exposure. Should there be an exploit in the Let’s Encrypt protocols, only one jail will be affected.
- Instead of configuring Let’s Encrypt in N locations, I am configuring it in one place.
- Not all of my SSL certificates will be associated with websites, so validation via HTTP was going to be a challenge. This meant dns-01* was the preferred authentication method for me. I was not about to allow DNS updates from every SSL certificate location. That would be asking for trouble.
*I found many references to dns-01 and the best definition I found is in the IETF draft ACME document.
There are many Let’s Encrypt clients. I selected acme.sh because Peter did, and because it’s a shell script. I like that.
Installing acme.sh on FreeBSD
On FreeBSD, acme.sh is available as the security/acme.sh port. By default, this port creates the the acme user with a home directory of /var/db/acme. Let’s Encrypt provisioning can, and should, be done as non-root. If you can do something as non-root, you should do it as non-root.
I do not like the standard acme.sh installation process. It installs the script into a local directory. I prefer to leave the acme.sh where it is installed by the port (specifically, /usr/local/sbin/acme.sh) and run it from there. It is because of that different approach that we need to manually create some configuration files.
What happens if you try running the acme.sh install process?
NOTE: Do not follow the steps in this section. They are for educational purposes only.
Please skip to the next section, nothing to see here.
The following is provided mostly for my own reference while I manually configure acme.sh in the next step. You can skip reading this section without missing anything.
[dan@certs:~/tmp] $ /usr/local/sbin/acme.sh --install [Thu Jun 29 12:23:01 UTC 2017] Installing to /usr/home/dan/.acme.sh cp: acme.sh: No such file or directory [Thu Jun 29 12:23:01 UTC 2017] Install failed, can not copy acme.sh
Oh. You really do need to be in that directory, just like the instructions say.
Let’s try that again.
[dan@certs:~/tmp] $ cd /usr/local/sbin [dan@certs:/usr/local/sbin] $ ./acme.sh --install [Thu Jun 29 12:23:22 UTC 2017] Installing to /usr/home/dan/.acme.sh [Thu Jun 29 12:23:22 UTC 2017] Installed to /usr/home/dan/.acme.sh/acme.sh [Thu Jun 29 12:23:22 UTC 2017] Installing alias to '/usr/home/dan/.profile' [Thu Jun 29 12:23:22 UTC 2017] OK, Close and reopen your terminal to start using acme.sh [Thu Jun 29 12:23:22 UTC 2017] Installing alias to '/usr/home/dan/.cshrc' [Thu Jun 29 12:23:22 UTC 2017] Installing cron job crontab: no crontab for dan crontab: no crontab for dan [Thu Jun 29 12:23:23 UTC 2017] Good, bash is found, so change the shebang to use bash as preferred. ./acme.sh: cannot create /usr/home/dan/.acme.sh/acme.sh: Permission denied ./acme.sh: cannot create /usr/home/dan/.acme.sh/acme.sh: Permission denied [Thu Jun 29 12:23:23 UTC 2017] OK [dan@certs:/usr/local/sbin] $
What did it do?
It created these files:
$ find .acme.sh .acme.sh .acme.sh/acme.sh.env .acme.sh/acme.sh.csh .acme.sh/account.conf .acme.sh/acme.sh
What is in those files?
[dan@certs:~/.acme.sh] $ cat acme.sh.env export LE_WORKING_DIR="/usr/home/dan/.acme.sh" alias acme.sh="/usr/home/dan/.acme.sh/acme.sh" [dan@certs:~/.acme.sh] $
[dan@certs:~/.acme.sh] $ cat acme.sh.csh setenv LE_WORKING_DIR "/usr/home/dan/.acme.sh" alias acme.sh "/usr/home/dan/.acme.sh/acme.sh"
[dan@certs:~/.acme.sh] $ cat account.conf #LOG_FILE="/usr/home/dan/.acme.sh/acme.sh.log" #LOG_LEVEL=1 #AUTO_UPGRADE="1" #NO_TIMESTAMP=1
It added these lines to these files:
$ grep acme ~/.profile ~/.cshrc /usr/home/dan/.profile:. "/usr/home/dan/.acme.sh/acme.sh.env" /usr/home/dan/.cshrc:source "/usr/home/dan/.acme.sh/acme.sh.csh"
It created this crontab:
$ crontab -l 22 0 * * * "/usr/home/dan/.acme.sh"/acme.sh --cron --home "/usr/home/dan/.acme.sh" > /dev/null
NOTE: the cronjob was eventually changed to:
7 22 * * * /usr/local/sbin/acme.sh --cron --home /var/db/acme/.acme.sh
re: Author’s advice.
What is this LE it refers to? Let’s Encrypt.
Plus, I don’t want that alias to be invoked. I want to use the acme.sh instance installed by the port, not a local copy.
The configuration files
I hope you ignored the previous section, thank you.
The current FreeBSD port automatically creates a user, acme, with a home directory of /var/db/acme. The following actions are performed as that user.
In this section, I will manually create the configuration files for acme.sh. I think this work will form the basis for a port update so that the port automagically creates these files for you, if they do not already exist. Before writing this blog post, I had a working acme.sh solution which I saved away, and now, as I type this, I am creating a new acme.sh installation from scratch.
Cleaning the account and starting fresh
NOTE: this section describes a destructive action. Be careful.
Here is what I did to start with a fresh Let’s Encrypt key. This may not apply to your configuration, but it works for how I have things set up.
[acme@certs ~]$ rm -rf .acme.sh/ca .acme.sh/http.header certs/* .rnd
This is the list of files I start with:
$ find . . ./.acme.sh ./.acme.sh/dnsapi ./Kcerts.int.unixathome.org.+165+59977.key ./Kcerts.int.unixathome.org.+165+59977.private ./certs
account.conf
My ~/.acme.sh/account.conf looks like this:
$ cat account.conf USER_PATH='/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin' NSUPDATE_SERVER="dns-hidden-master.int.unixathome.org" NSUPDATE_KEY="/var/db/acme/Kcerts.int.unixathome.org.+165+59977.key" DEFAULT_DNS_SLEEP="10" CERT_HOME="/var/db/acme/certs" LOG_FILE='/var/db/acme/acme.sh.log'
Lines 4 and 5 define environment variables used by the dns_nsupdate.sh script which is included with the FreeBSD port of acme.sh (see /usr/local/share/examples/acme.sh/dnsapi). The Kcerts file is explained in my recent post on creating a key for nsupdate.
Line 6 indicates how long (in seconds) to wait for DNS propagation. My value is low, for testing, but I would use something like 60 in production. Longer waits are just fine. There is no rush in production.
Line 7 specifies the key length for the certificates. I want 4KB certificates.
Line 8 indicates that new certificates will be placed in the specified directory. Keys will also be placed in this directory, therefore, it must not be world readable.
Line 9 specifies the log file to use.
Running acme.sh for the first time
acme.sh tries to do as much for you as it can. Read below for more information.
You should note that I have specified –staging. There are limits on how many live certificates you can create. When testing, always use –staging. Such certificates will not be useful in public.
[acme@certs ~]$ acme.sh --staging --issue --dns dns_nsupdate -d lists.unixathome.org [Fri Jun 30 20:50:27 UTC 2017] Using stage api:https://acme-staging.api.letsencrypt.org [Fri Jun 30 20:50:28 UTC 2017] Registering account [Fri Jun 30 20:50:29 UTC 2017] Registered [Fri Jun 30 20:50:29 UTC 2017] Update success. [Fri Jun 30 20:50:29 UTC 2017] ACCOUNT_THUMBPRINT='BYEw6p8pAnuj6LEO-bM-rf_NxosNa0HVmLDE5NsGVog' [Fri Jun 30 20:50:29 UTC 2017] Creating domain key [Fri Jun 30 20:50:29 UTC 2017] Single domain='lists.unixathome.org' [Fri Jun 30 20:50:29 UTC 2017] Getting domain auth token for each domain [Fri Jun 30 20:50:29 UTC 2017] Getting webroot for domain='lists.unixathome.org' [Fri Jun 30 20:50:29 UTC 2017] Getting new-authz for domain='lists.unixathome.org' [Fri Jun 30 20:50:30 UTC 2017] The new-authz request is ok. [Fri Jun 30 20:50:30 UTC 2017] Found domain api file: /var/db/acme/.acme.sh/dnsapi/dns_nsupdate.sh [Fri Jun 30 20:50:30 UTC 2017] adding _acme-challenge.lists.unixathome.org. 60 in txt "DlyqdRNT7WKpetBJx4DsVsA-U_zblScu-O95EaBD4VU" [Fri Jun 30 20:50:30 UTC 2017] Sleep 10 seconds for the txt records to take effect [Fri Jun 30 20:50:41 UTC 2017] Verifying:lists.unixathome.org [Fri Jun 30 20:50:44 UTC 2017] Success [Fri Jun 30 20:50:44 UTC 2017] removing _acme-challenge.lists.unixathome.org. txt [Fri Jun 30 20:50:44 UTC 2017] Verify finished, start to sign. [Fri Jun 30 20:50:45 UTC 2017] Cert success. -----BEGIN CERTIFICATE----- MIIE7DCCA9SgAwIBAgITAPr8V+8RKtnmcj7aForvT4rYVzANBgkqhkiG9w0BAQsF ADAiMSAwHgYDVQQDDBdGYWtlIExFIEludGVybWVkaWF0ZSBYMTAeFw0xNzA2MzAx OTUxMDBaFw0xNzA5MjgxOTUxMDBaMB8xHTAbBgNVBAMTFGxpc3RzLnVuaXhhdGhv bWUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA85soDhohxOuG amZyAOtmTyc90Y44VkEifrsAoYNOIKewTybmZ5UrVXqPd6txGFdhzJNpvuJKJ0RV zo7ZPvCpIegIx8M3hrFluacuzWpEByqAQaY+9a063oar6reVWsPf/LPJqij78SAh 7V+QHy1kM5eeUS/B1OLqj0aoyWLdNA5GyGWmWOv7WYh/kmu9VcQCQAI7L8qWYj7r M0pXDMTMP+td9ZeMAJZGHPolqypJFLEn4rU0UDjTZd3nY+z7HQIKe2ldEwel++kn rqr+xcAZJL42WH+BDof0U18VafuN6lLeYZCyVjhX2a2ySboxxvKsfEOW+vadfzJJ EaBLfrE+VQIDAQABo4ICHDCCAhgwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQgv0cy YBgtejOPH9JvBABUt4QrLTAfBgNVHSMEGDAWgBTAzANGuVggzFxycPPhLssgpvVo OjB3BggrBgEFBQcBAQRrMGkwMgYIKwYBBQUHMAGGJmh0dHA6Ly9vY3NwLnN0Zy1p bnQteDEubGV0c2VuY3J5cHQub3JnMDMGCCsGAQUFBzAChidodHRwOi8vY2VydC5z dGctaW50LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYDVR0RBBgwFoIUbGlzdHMudW5p eGF0aG9tZS5vcmcwgf4GA1UdIASB9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8T AQEBMIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCB qwYIKwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJl bGllZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRh bmNlIHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczov L2xldHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEA zRQHa16e/jbtkewtro1I2aJBhX6FVQbA7aWPMpT+NZVqOTQNMp2kYfdxcvhQDavA uBqPfjZHRY4pydPN53vXnRHA8FCKfTXGeS68ZxzEu4CQ1YBLBqCPMDzawmVYkBjD +E+AuFpFr3YRMppsGt5GUUsoKkUaUZQEMhyXdL+r1hzKQptinvHr7w1YRAdeg6ac aMBAPk2hdUNS57iz9nxsvdhLP6qCKakREKvoP/xP2N/fgZbbpaFDDJGnlcfeGYKx B5LWTFYUBJqPsVYG6rD8j3f7LWzVPkq2d4yj1pR+vaqb+C/POZq0Kvrg74Fo8Hdq U/tzny/gcGi2wcjuLfB7Wg== -----END CERTIFICATE----- [Fri Jun 30 20:50:45 UTC 2017] Your cert is in /var/db/acme/certs/lists.unixathome.org/lists.unixathome.org.cer [Fri Jun 30 20:50:45 UTC 2017] Your cert key is in /var/db/acme/certs/lists.unixathome.org/lists.unixathome.org.key [Fri Jun 30 20:50:45 UTC 2017] The intermediate CA cert is in /var/db/acme/certs/lists.unixathome.org/ca.cer [Fri Jun 30 20:50:45 UTC 2017] And the full chain certs is there: /var/db/acme/certs/lists.unixathome.org/fullchain.cer [acme@certs ~]$
On line 3, you can see the registration process starting. This results in two files, a certificate and a key:
.acme.sh/ca/acme-staging.api.letsencrypt.org/account.key .acme.sh/ca/acme-staging.api.letsencrypt.org/account.json
On line 13, the authorization process begins.
As you can see, they are prefixed with acme-staging because we are running in –staging.
Viewing the newly obtained certificate, we see:
[acme@certs ~]$ openssl x509 -text -noout -in ./certs/lists.unixathome.org/lists.unixathome.org.cer Certificate: Data: Version: 3 (0x2) Serial Number: fa:fc:57:ef:11:2a:d9:e6:72:3e:da:16:8a:ef:4f:8a:d8:57 Signature Algorithm: sha256WithRSAEncryption Issuer: CN=Fake LE Intermediate X1 Validity Not Before: Jun 30 19:51:00 2017 GMT Not After : Sep 28 19:51:00 2017 GMT Subject: CN=lists.unixathome.org Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:f3:9b:28:0e:1a:21:c4:eb:86:6a:66:72:00:eb: 66:4f:27:3d:d1:8e:38:56:41:22:7e:bb:00:a1:83: 4e:20:a7:b0:4f:26:e6:67:95:2b:55:7a:8f:77:ab: 71:18:57:61:cc:93:69:be:e2:4a:27:44:55:ce:8e: d9:3e:f0:a9:21:e8:08:c7:c3:37:86:b1:65:b9:a7: 2e:cd:6a:44:07:2a:80:41:a6:3e:f5:ad:3a:de:86: ab:ea:b7:95:5a:c3:df:fc:b3:c9:aa:28:fb:f1:20: 21:ed:5f:90:1f:2d:64:33:97:9e:51:2f:c1:d4:e2: ea:8f:46:a8:c9:62:dd:34:0e:46:c8:65:a6:58:eb: fb:59:88:7f:92:6b:bd:55:c4:02:40:02:3b:2f:ca: 96:62:3e:eb:33:4a:57:0c:c4:cc:3f:eb:5d:f5:97: 8c:00:96:46:1c:fa:25:ab:2a:49:14:b1:27:e2:b5: 34:50:38:d3:65:dd:e7:63:ec:fb:1d:02:0a:7b:69: 5d:13:07:a5:fb:e9:27:ae:aa:fe:c5:c0:19:24:be: 36:58:7f:81:0e:87:f4:53:5f:15:69:fb:8d:ea:52: de:61:90:b2:56:38:57:d9:ad:b2:49:ba:31:c6:f2: ac:7c:43:96:fa:f6:9d:7f:32:49:11:a0:4b:7e:b1: 3e:55 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: 20:BF:47:32:60:18:2D:7A:33:8F:1F:D2:6F:04:00:54:B7:84:2B:2D X509v3 Authority Key Identifier: keyid:C0:CC:03:46:B9:58:20:CC:5C:72:70:F3:E1:2E:CB:20:A6:F5:68:3A Authority Information Access: OCSP - URI:http://ocsp.stg-int-x1.letsencrypt.org CA Issuers - URI:http://cert.stg-int-x1.letsencrypt.org/ X509v3 Subject Alternative Name: DNS:lists.unixathome.org X509v3 Certificate Policies: Policy: 2.23.140.1.2.1 Policy: 1.3.6.1.4.1.44947.1.1.1 CPS: http://cps.letsencrypt.org User Notice: Explicit Text: This Certificate may only be relied upon by Relying Parties and only in accordance with the Certificate Policy found at https://letsencrypt.org/repository/ Signature Algorithm: sha256WithRSAEncryption cd:14:07:6b:5e:9e:fe:36:ed:91:ec:2d:ae:8d:48:d9:a2:41: 85:7e:85:55:06:c0:ed:a5:8f:32:94:fe:35:95:6a:39:34:0d: 32:9d:a4:61:f7:71:72:f8:50:0d:ab:c0:b8:1a:8f:7e:36:47: 45:8e:29:c9:d3:cd:e7:7b:d7:9d:11:c0:f0:50:8a:7d:35:c6: 79:2e:bc:67:1c:c4:bb:80:90:d5:80:4b:06:a0:8f:30:3c:da: c2:65:58:90:18:c3:f8:4f:80:b8:5a:45:af:76:11:32:9a:6c: 1a:de:46:51:4b:28:2a:45:1a:51:94:04:32:1c:97:74:bf:ab: d6:1c:ca:42:9b:62:9e:f1:eb:ef:0d:58:44:07:5e:83:a6:9c: 68:c0:40:3e:4d:a1:75:43:52:e7:b8:b3:f6:7c:6c:bd:d8:4b: 3f:aa:82:29:a9:11:10:ab:e8:3f:fc:4f:d8:df:df:81:96:db: a5:a1:43:0c:91:a7:95:c7:de:19:82:b1:07:92:d6:4c:56:14: 04:9a:8f:b1:56:06:ea:b0:fc:8f:77:fb:2d:6c:d5:3e:4a:b6: 77:8c:a3:d6:94:7e:bd:aa:9b:f8:2f:cf:39:9a:b4:2a:fa:e0: ef:81:68:f0:77:6a:53:fb:73:9f:2f:e0:70:68:b6:c1:c8:ee: 2d:f0:7b:5a [acme@certs ~]$
Line 8 is important. It indicates we obtained this cert via –staging.
As this point, there are the files I have:
$ find . . ./.acme.sh ./.acme.sh/ca ./.acme.sh/ca/acme-staging.api.letsencrypt.org ./.acme.sh/ca/acme-staging.api.letsencrypt.org/account.key ./.acme.sh/ca/acme-staging.api.letsencrypt.org/account.json ./.acme.sh/ca/acme-staging.api.letsencrypt.org/ca.conf ./.acme.sh/account.conf ./.acme.sh/account.conf.sample ./.acme.sh/dnsapi ./.acme.sh/http.header ./Kcerts.int.unixathome.org.+165+59977.private ./Kcerts.int.unixathome.org.+165+59977.key ./certs ./certs/lists.unixathome.org ./certs/lists.unixathome.org/lists.unixathome.org.key ./certs/lists.unixathome.org/fullchain.cer ./certs/lists.unixathome.org/lists.unixathome.org.csr.conf ./certs/lists.unixathome.org/lists.unixathome.org.cer ./certs/lists.unixathome.org/lists.unixathome.org.conf ./certs/lists.unixathome.org/lists.unixathome.org.csr ./certs/lists.unixathome.org/ca.cer
Getting a second cert
In the previous section, I obtained a cert for lists.unixathome.org. Now let’s get one for www.unixathome.org.
$ acme.sh --staging --issue --dns dns_nsupdate -d www.unixathome.org [Fri Jun 30 21:10:29 UTC 2017] Using stage api:https://acme-staging.api.letsencrypt.org [Fri Jun 30 21:10:29 UTC 2017] Single domain='www.unixathome.org' [Fri Jun 30 21:10:29 UTC 2017] Getting domain auth token for each domain [Fri Jun 30 21:10:29 UTC 2017] Getting webroot for domain='www.unixathome.org' [Fri Jun 30 21:10:29 UTC 2017] Getting new-authz for domain='www.unixathome.org' [Fri Jun 30 21:10:32 UTC 2017] The new-authz request is ok. [Fri Jun 30 21:10:32 UTC 2017] Found domain api file: /var/db/acme/.acme.sh/dnsapi/dns_nsupdate.sh [Fri Jun 30 21:10:32 UTC 2017] adding _acme-challenge.www.unixathome.org. 60 in txt "eMwKmRpe6zkx_b1u1WZyCP01ZdqBkF9j4wlpBudkKb8" [Fri Jun 30 21:10:32 UTC 2017] Sleep 10 seconds for the txt records to take effect [Fri Jun 30 21:10:44 UTC 2017] Verifying:www.unixathome.org [Fri Jun 30 21:10:46 UTC 2017] Success [Fri Jun 30 21:10:46 UTC 2017] removing _acme-challenge.www.unixathome.org. txt [Fri Jun 30 21:10:46 UTC 2017] Verify finished, start to sign. [Fri Jun 30 21:10:47 UTC 2017] Cert success. -----BEGIN CERTIFICATE----- MIIE6DCCA9CgAwIBAgITAPqSDeV9j0oajwBNjbstp4DQmzANBgkqhkiG9w0BAQsF ADAiMSAwHgYDVQQDDBdGYWtlIExFIEludGVybWVkaWF0ZSBYMTAeFw0xNzA2MzAy MDExMDBaFw0xNzA5MjgyMDExMDBaMB0xGzAZBgNVBAMTEnd3dy51bml4YXRob21l Lm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOaDCsU5c433w+f JQvPZXkzVMS1GHRrYXfe1cx8ThYTICPqECIlg02e5YbFmZQDbgt8REdt5nMqR6t3 JlaAi6tthX/qjgLfRE6NQzUQS2R73Etwy+AlWXOe4RdkWd3iSA/LixqJZT9gM4O8 yB+ZyhZ9Pw7tDlINketLkWB3zPkj4NVmHaJ4eWTHqR0pT9TFS/AQVG+qtpmLvwaO KYCvrkX/cItdXXHyQJuJ1+JMJMsmW5S7Ky0l1VGbf20PdsO4re++mAWDRvpO3RcS L/bJJuKXair444DhUpHX76+Y3Zz827ib6IWc8zp+FPbcuBCMV+7oGuMRYgkCzX/u hjjaB1kCAwEAAaOCAhowggIWMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggr BgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUxebNiKsz S79Zdy9eYzDFKUz6ZucwHwYDVR0jBBgwFoAUwMwDRrlYIMxccnDz4S7LIKb1aDow dwYIKwYBBQUHAQEEazBpMDIGCCsGAQUFBzABhiZodHRwOi8vb2NzcC5zdGctaW50 LXgxLmxldHNlbmNyeXB0Lm9yZzAzBggrBgEFBQcwAoYnaHR0cDovL2NlcnQuc3Rn LWludC14MS5sZXRzZW5jcnlwdC5vcmcvMB0GA1UdEQQWMBSCEnd3dy51bml4YXRo b21lLm9yZzCB/gYDVR0gBIH2MIHzMAgGBmeBDAECATCB5gYLKwYBBAGC3xMBAQEw gdYwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3JnMIGrBggr BgEFBQcCAjCBngyBm1RoaXMgQ2VydGlmaWNhdGUgbWF5IG9ubHkgYmUgcmVsaWVk IHVwb24gYnkgUmVseWluZyBQYXJ0aWVzIGFuZCBvbmx5IGluIGFjY29yZGFuY2Ug d2l0aCB0aGUgQ2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vbGV0 c2VuY3J5cHQub3JnL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAwqYno tqFqdFxAxR1DvACweV8Ao9iTyn0cAX2heuS0D+wjNPZRXpAPSeZKlfuYrlzBbOdg 8/pA1+4PO9VpIIT0V7fTBW40QljXZap+WciPEpkmSuvm2xNRA5nXtn9FntY+X6A+ E5XeaiQ7/e+qczmAFSKzLj3vXEk2ThTbFbC5jQEaX7Uwg2aYbZH+PJIof0lovICB TeVpBMPwQCjJ60/aiMh8T0ZSNdF87wGJyLFtBLWCRbYMfRoySwr1aXtNxINoaOl4 KmKCk7CKDGjdRqd8qpWto3ymHdV1asIC3X1W+8kYLfMoHZsXH6t+0yOwUnUvRzDq Pc7nb5W8NfThdMnR -----END CERTIFICATE----- [Fri Jun 30 21:10:47 UTC 2017] Your cert is in /var/db/acme/certs/www.unixathome.org/www.unixathome.org.cer [Fri Jun 30 21:10:47 UTC 2017] Your cert key is in /var/db/acme/certs/www.unixathome.org/www.unixathome.org.key [Fri Jun 30 21:10:47 UTC 2017] The intermediate CA cert is in /var/db/acme/certs/www.unixathome.org/ca.cer [Fri Jun 30 21:10:47 UTC 2017] And the full chain certs is there: /var/db/acme/certs/www.unixathome.org/fullchain.cer [acme@certs ~]$
What new files do I have now?
/certs/www.unixathome.org ./certs/www.unixathome.org/ca.cer ./certs/www.unixathome.org/fullchain.cer ./certs/www.unixathome.org/www.unixathome.org.cer ./certs/www.unixathome.org/www.unixathome.org.conf ./certs/www.unixathome.org/www.unixathome.org.csr ./certs/www.unixathome.org/www.unixathome.org.csr.conf ./certs/www.unixathome.org/www.unixathome.org.key
I think you can see where this is going.
Getting a real certificate
Everything up to now has been in –staging. Now we go live:
[acme@certs ~]$ acme.sh --issue --dns dns_nsupdate -d certs.unixathome.org [Tue Jul 4 20:38:07 UTC 2017] Creating domain key [Tue Jul 4 20:38:07 UTC 2017] Single domain='certs.unixathome.org' [Tue Jul 4 20:38:07 UTC 2017] Getting domain auth token for each domain [Tue Jul 4 20:38:07 UTC 2017] Getting webroot for domain='certs.unixathome.org' [Tue Jul 4 20:38:07 UTC 2017] Getting new-authz for domain='certs.unixathome.org' [Tue Jul 4 20:38:10 UTC 2017] The new-authz request is ok. [Tue Jul 4 20:38:10 UTC 2017] certs.unixathome.org is already verified, skip dns-01. [Tue Jul 4 20:38:10 UTC 2017] Verify finished, start to sign. [Tue Jul 4 20:38:11 UTC 2017] Cert success. -----BEGIN CERTIFICATE----- MIIFCzCCA/OgAwIBAgISAzFhPgUiIxRB9Df/0W27wy1VMA0GCSqGSIb3DQEBCwUA MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzA3MDQxOTM4MDBaFw0x NzEwMDIxOTM4MDBaMB8xHTAbBgNVBAMTFGNlcnRzLnVuaXhhdGhvbWUub3JnMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqyxK6kW7TGbIjffYZI2omOOT MPogmLnQYHn+efsp4RqzRK2QTh0pMW/7BnwPKXNExfWv3ymp4G7lvrUDUQNNKjyi fG6UL/W+EHVAW72Vx3iTdd1OLBvjTkPpP25wNLXEroJnsLLkJZODi57d8MTB71Vq YVB6eYEv+1wrZ/o7mrcLEq+Tl5SLpmWEcoLF/DZOEEZ8Uksbh1fgsAJPRju0PgfX nA96YBqQOViOQOuTznLO/gVBOhXbVlw7Dv/KBlUpvCNYKiNAhHKmCHx4oAzBbCdy tJFBqPZGmxaiTxwouLfkbl9s/wuMf0oFAwZoZ3lKmQ993olREqZvwKEUB6RAGQID AQABo4ICFDCCAhAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRnTjSuCVhE3wUvsbp3 /7IvpJQfiDAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEF BQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5j cnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5j cnlwdC5vcmcvMB8GA1UdEQQYMBaCFGNlcnRzLnVuaXhhdGhvbWUub3JnMIH+BgNV HSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsrBgEEAYLfEwEBATCB1jAmBggrBgEFBQcC ARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwgasGCCsGAQUFBwICMIGeDIGb VGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25seSBiZSByZWxpZWQgdXBvbiBieSBSZWx5 aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0 aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQgaHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcv cmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAFDMUvXunbV1CgPxyy2Aw8TM zvmCjQiWMalvLMVqL3DXjLyt8U0ckHeFR+crqH1aiZXbDtbTWQQpDFDbJubzk/0p vmkqU5YeSd2M5eIYPNDnO4SqvCv1i94a7Flhr3bFpwLgHFBAfmIHL7TCl+tI9eIJ pGQgSW2zJ7yqhj1Kmi1yLlf2hpGJEEi0eIj0rFgGXOx2k2Tj0QUlNI5ZCtw88wO6 9GCH77KfqsLKHznGOl9yZCWFg7pKYCFOiWUXb5GgON9rWrj/Rzm4AaD9k0TdQMEd t4jMsLw8R7Lh8sHX4t5FsL9l73I6lVAHEkSdtjI1Ew6GM+uLCUytYDMhWwDLmQo= -----END CERTIFICATE----- [Tue Jul 4 20:38:11 UTC 2017] Your cert is in /var/db/acme/certs/certs.unixathome.org/certs.unixathome.org.cer [Tue Jul 4 20:38:11 UTC 2017] Your cert key is in /var/db/acme/certs/certs.unixathome.org/certs.unixathome.org.key [Tue Jul 4 20:38:11 UTC 2017] The intermediate CA cert is in /var/db/acme/certs/certs.unixathome.org/ca.cer [Tue Jul 4 20:38:11 UTC 2017] And the full chain certs is there: /var/db/acme/certs/certs.unixathome.org/fullchain.cer [acme@certs ~]$
BANG! There I have a legit cert, which you can see now at https://certs.unixathome.org/
You will note that line 8 shows that I am already verified to produce certificates for this host. Thus dns-01 validation was skipped. This is because the above was not the first time I created a certificate for that host, but I had purposely deleted the local cert, so a new key was generated and a new certificate issues. This was done for testing purposes.
But wait, there’s more!
This blog post is just about creating certs. I have more to write about how I distribute those certificates to where they are used. That will be coming soon.