Acme.sh全自动获取SSL通配符证书
Here I’m gonna show you a quick how-to on obtaining a wildcard SSL cert from Let’s Encrypt with the “pure shell written” acme.sh, which is simple, light-weight and far beyond flexible.
And you may already aware that I’ve an earlier post on doing this with another tool called certbot-auto, well, unfortuantely it’s… kinda still working… but having no support or further update anymore. As for the “official successor” of the certbot-auto? It seems the official guys have decided to walk step and step closer into the mire, with that good-looking but evil-inside snapd… oh, don’t even say that word again. It’s weird enough – I saw nothing around Canonical brand on sponsors list from homepage of Let’s Encrypt. That’s another topic anyway, a wildcard SSL cert for free is still worth my sincere appreciation in this case.
今天简单聊下如何使用acme.sh来获取通配符证书,纯shell工具比之前聊过的certbot-auto更为简单、轻量且灵活。此外不幸的是,半年不见certbot已然走上邪路,奇怪的是Let’s Encrypt首页赞助商清单里并未发现Canonical在列,让我倍感意外。
废话少叙,先装为敬。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
[root@aqui-test ~]# curl https://get.acme.sh | sh % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 937 0 937 0 0 445 0 --:--:-- 0:00:02 --:--:-- 445 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 204k 100 204k 0 0 33335 0 0:00:06 0:00:06 --:--:-- 28373 [Sat Feb 27 23:14:42 CST 2021] Installing from online archive. [Sat Feb 27 23:14:42 CST 2021] Downloading https://github.com/acmesh-official/acme.sh/archive/master.tar.gz [Sat Feb 27 23:15:47 CST 2021] Extracting master.tar.gz [Sat Feb 27 23:15:47 CST 2021] It is recommended to install socat first. [Sat Feb 27 23:15:47 CST 2021] We use socat for standalone server if you use standalone mode. [Sat Feb 27 23:15:47 CST 2021] If you don't use standalone mode, just ignore this warning. [Sat Feb 27 23:15:47 CST 2021] Installing to /root/.acme.sh [Sat Feb 27 23:15:47 CST 2021] Installed to /root/.acme.sh/acme.sh [Sat Feb 27 23:15:47 CST 2021] Installing alias to '/root/.bashrc' [Sat Feb 27 23:15:47 CST 2021] OK, Close and reopen your terminal to start using acme.sh [Sat Feb 27 23:15:47 CST 2021] Installing alias to '/root/.cshrc' [Sat Feb 27 23:15:47 CST 2021] Installing alias to '/root/.tcshrc' [Sat Feb 27 23:15:47 CST 2021] Installing cron job [Sat Feb 27 23:15:48 CST 2021] Good, bash is found, so change the shebang to use bash as preferred. [Sat Feb 27 23:15:49 CST 2021] OK [Sat Feb 27 23:15:49 CST 2021] Install success! [root@aqui-test ~]# |
安装过程中会自动创建cronjob,如果不想自动创建,安装时要加个参数,也可以手动把cronjob删掉(则证书不会自动展期)。
1 2 3 4 |
[root@aqui-test ~]# crontab -l # m h dom mon dow command 47 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null [root@aqui-test ~]# |
此时把阿里云key和secret填入环境变量(建议使用RAM账户,风险最小化)。
1 2 |
[root@aqui-test ~]# export Ali_Key="L123456789q" [root@aqui-test ~]# export Ali_Secret="j123456789l" |
然后一句话申请wildcard(通配符)证书。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
[root@aqui-test ~]# source ~/.bashrc [root@aqui-test ~]# acme.sh --issue -d example.com -d '*.example.com' --dns dns_ali [Sat Feb 27 23:19:06 CST 2021] Using CA: https://acme-v02.api.letsencrypt.org/directory [Sat Feb 27 23:19:06 CST 2021] Create account key ok. [Sat Feb 27 23:19:06 CST 2021] Registering account: https://acme-v02.api.letsencrypt.org/directory [Sat Feb 27 23:19:09 CST 2021] Registered [Sat Feb 27 23:19:09 CST 2021] ACCOUNT_THUMBPRINT='o1234567890' [Sat Feb 27 23:19:09 CST 2021] Creating domain key [Sat Feb 27 23:19:09 CST 2021] The domain key is here: /root/.acme.sh/example.com/example.com.key [Sat Feb 27 23:19:09 CST 2021] Multi domain='DNS:example.com,DNS:*.example.com' [Sat Feb 27 23:19:09 CST 2021] Getting domain auth token for each domain [Sat Feb 27 23:19:55 CST 2021] Getting webroot for domain='example.com' [Sat Feb 27 23:19:55 CST 2021] Getting webroot for domain='*.example.com' [Sat Feb 27 23:19:56 CST 2021] Adding txt value: -K123456789U for domain: _acme-challenge.example.com [Sat Feb 27 23:20:00 CST 2021] The txt record is added: Success. [Sat Feb 27 23:20:00 CST 2021] Adding txt value: J123456789o for domain: _acme-challenge.example.com [Sat Feb 27 23:20:04 CST 2021] The txt record is added: Success. [Sat Feb 27 23:20:04 CST 2021] Let's check each DNS record now. Sleep 20 seconds first. [Sat Feb 27 23:20:25 CST 2021] You can use '--dnssleep' to disable public dns checks. [Sat Feb 27 23:20:25 CST 2021] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck [Sat Feb 27 23:20:25 CST 2021] Checking example.com for _acme-challenge.example.com [Sat Feb 27 23:20:34 CST 2021] Domain example.com '_acme-challenge.example.com' success. [Sat Feb 27 23:20:34 CST 2021] Checking example.com for _acme-challenge.example.com [Sat Feb 27 23:20:40 CST 2021] Domain example.com '_acme-challenge.example.com' success. [Sat Feb 27 23:20:40 CST 2021] All success, let's return [Sat Feb 27 23:20:40 CST 2021] Verifying: example.com [Sat Feb 27 23:20:50 CST 2021] Success [Sat Feb 27 23:20:50 CST 2021] Verifying: *.example.com [Sat Feb 27 23:20:56 CST 2021] Success [Sat Feb 27 23:20:56 CST 2021] Removing DNS records. [Sat Feb 27 23:20:56 CST 2021] Removing txt: -K123456789U for domain: _acme-challenge.example.com [Sat Feb 27 23:21:01 CST 2021] Removed: Success [Sat Feb 27 23:21:01 CST 2021] Removing txt: J123456789o for domain: _acme-challenge.example.com [Sat Feb 27 23:21:07 CST 2021] Removed: Success [Sat Feb 27 23:21:07 CST 2021] Verify finished, start to sign. [Sat Feb 27 23:21:07 CST 2021] Lets finalize the order. [Sat Feb 27 23:21:07 CST 2021] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/123456789/123456789' [Sat Feb 27 23:21:10 CST 2021] Downloading cert. [Sat Feb 27 23:21:10 CST 2021] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/039bfa3afcace39d60f023a0b6222406329b' [Sat Feb 27 23:21:15 CST 2021] Cert success. -----BEGIN CERTIFICATE----- XxxxxxxxxxxxxxxxxxxxxxxxxxxnnnnnnnnnnnNNNNNnnnnnnnnnnNNNNNNnnnnn XxxxxxxxxxxxxxxxxxxxxxxxxxxnnnnnnnnnnnNNNNNnnnnnnnnnnNNNNNNnnnnn XxxxxxxxxxxxxxxxxxxxxxxxxxxnnnnnnnnnnnNNNNNnnnnn -----END CERTIFICATE----- [Sat Feb 27 23:21:15 CST 2021] Your cert is in /root/.acme.sh/example.com/example.com.cer [Sat Feb 27 23:21:15 CST 2021] Your cert key is in /root/.acme.sh/example.com/example.com.key [Sat Feb 27 23:21:15 CST 2021] The intermediate CA cert is in /root/.acme.sh/example.com/ca.cer [Sat Feb 27 23:21:15 CST 2021] And the full chain certs is there: /root/.acme.sh/example.com/fullchain.cer [root@aqui-test ~]# |
这样锃光瓦亮的证书就到手了,接下来把证书“安装”到nginx(apache之类都行,无所谓)。
之所以安装二字打引号,是因为其实无论证书文件存放何处,无非都是web服务器配置的问题,而acme.sh的文档里建议呢,还是“安装”一下,而非直接在acme的home目录下使用,是该工具不保证今后证书的存储路径不做变更,所以这里有一个官方的安装指令。
1 2 3 4 5 6 7 |
[root@aqui-test ~]# mkdir -p /etc/nginx/ssl/example.com [root@aqui-test ~]# acme.sh --install-cert -d example.com --key-file /etc/nginx/ssl/example.com/key.pem --fullchain-file /etc/nginx/ssl/example.com/cert.pem --reloadcmd "/bin/systemctl force-reload nginx" [Sat Feb 27 23:28:23 CST 2021] Installing key to:/etc/nginx/ssl/example.com/key.pem [Sat Feb 27 23:28:23 CST 2021] Installing full chain to:/etc/nginx/ssl/example.com/cert.pem [Sat Feb 27 23:28:23 CST 2021] Run reload cmd: /bin/systemctl force-reload nginx [Sat Feb 27 23:28:24 CST 2021] Reload success [root@aqui-test ~]# |
好人做到底,多写一下nginx配置文件,启用SSL的玩法。其中 dhparam.pem 是可选的,建议自制一个,反正不费劲,据称可以提高ssllabs.com评分;如果没做,那么配置文件里不要加这一行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
[root@aqui-test ~]# openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 Generating DH parameters, 2048 bit long safe prime, generator 2 This is going to take a long time ..........................................................................* [root@aqui-test ~]# cat /etc/nginx/conf.d/something.conf # # The something server # server { listen 80; server_name somthing.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl; server_name something.example.com; charset utf-8; client_max_body_size 20M; sendfile on; keepalive_timeout 60; keepalive_requests 20; large_client_header_buffers 8 32k; send_timeout 20; # acme.sh生成并安装的ssl cert ssl_certificate /etc/nginx/ssl/example.com/cert.pem; ssl_certificate_key /etc/nginx/ssl/example.com/key.pem; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets on; #自制的dhparam.pem放在这里 ssl_dhparam /etc/nginx/ssl/dhparam.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 一般推荐使用的ssl_ciphers值: https://wiki.mozilla.org/Security/Server_Side_TLS ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK'; ssl_prefer_server_ciphers on; location / { #bla bla bla... } } [root@aqui-test ~]# |
最后就剩下自动续期和自动安装了,前者是acme.sh已经替你做好了cronjob(看起来是每天续期,实际运行一下就知道了,不到60天的话只检查,不真正触发);后者感觉没有,我多写一个cron试试看,应该可以实现自动安装。
1 2 3 4 5 |
[root@aqui-test ~]# crontab -l # m h dom mon dow command 20 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null 25 2 16,28 */1 * "/root/.acme.sh"/acme.sh --home "/root/.acme.sh" --install-cert -d example.com --key-file /etc/nginx/ssl/example.com/key.pem --fullchain-file /etc/nginx/ssl/example.com/cert.pem --reloadcmd "/bin/systemctl force-reload nginx" [root@aqui-test ~]# |
至于通配符证书的多机共用,其实不用每台机器都安装acme.sh,不仅过程繁琐,且对Let’s Encrypt也是一种资源浪费。
只要让另外一台的root可以pubkey登录本机的root(关掉密码认证)就可以即时同步更新证书了。
1 2 3 4 |
[root@aqui-another ~]# mkdir -p /etc/nginx/ssl/example.com [root@aqui-another ~]# crontab -l 30 3 16,28 */1 * /usr/bin/rsync -avz root@172.34.56.78:/etc/nginx/ssl/ /etc/nginx/ssl --delete > /tmp/rsync_cert.log 2>&1 && /bin/systemctl force-reload nginx.service >> /tmp/rsync_cert.log 2>&1 [root@aqui-test ~]# |
大致就是这样了,这几个定时安装和同步的cronjob,根据OS的实际差异可能有所变化,不一而足。
附一下继续使用certbot-auto看到的关于不再支持的提示信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
[root@aqui-test ~]# cat /tmp/certbot_auto_renew.log Your system is not supported by certbot-auto anymore. certbot-auto and its Certbot installation will no longer receive updates. You will not receive any bug fixes including those fixing server compatibility or security problems. Please visit https://certbot.eff.org/ to check for other alternatives. Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Processing /etc/letsencrypt/renewal/example.com.conf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cert is due for renewal, auto-renewing... Non-interactive renewal: random delay of 191.929778416 seconds Plugins selected: Authenticator manual, Installer None Renewing an existing certificate for *.example.com Performing the following challenges: dns-01 challenge for example.com Running manual-auth-hook command: /home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh python aly add Waiting for verification... Cleaning up challenges Running manual-cleanup-hook command: /home/py27/certbot-letencrypt-wildcardcertificates-alydns-au/au.sh python aly clean Running deploy-hook command: /bin/systemctl restart nginx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - new certificate deployed without reload, fullchain is /etc/letsencrypt/live/example.com/fullchain.pem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/example.com/fullchain.pem (success) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
文章的脚注信息由WordPress的wp-posturl插件自动生成