docker使用certbot获取证书(后续尝试定时续期)
背景
没啥背景,就是需要搞证书,花钱的证书买不起,就只能白嫖了,白嫖肯定就只有let‘s encrypt,没啥说的直接开干。
我准备了三个域名,www.xxx.com,api.xxx.com和admin.xxx.com,
zerossl
差了let‘s encrype的官方文档。有很多的acme的客户端。因为我基本都会优先考虑容器,发现docker哪里有个zerossl,然后也去研究了一下,zerossl的官网(https://zerossl.com/)也提供了很多关于证书的相关接口,对接他的接口我觉得应该也可以。但是我没有,因为我觉得都是ACME的客户端实现,我为啥还要再去实现一遍。没必要。然后就去研究了一下zerossl的docker容器。搜索引擎关于zerossl的容器资料特别少,它的官方主页(https://hub.docker.com/r/zerossl/client/)也写的有点复杂,反正我没时间出来,(总是会提示method not allowed),所以最终还是放弃了,回到最原始的certbot
以上是一堆废话,下面开始正文
certbot
certbot其实也有对应的docker容器(https://hub.docker.com/r/certbot/certbot)版本,这也是我后面才发现的,因为他官方文档写的docker客户端是zerossl。
certbot使用docker的文档地址:https://certbot.eff.org/docs/install.html#running-with-docker
不说废话了,直接拉取镜像,然后使用命令查看帮助信息
docker run -it --rm certbot/certbot --help
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ... Certbot can obtain and install HTTPS/TLS/SSL certificates. By default, it will attempt to use a webserver both for obtaining and installing the certificate. The most common SUBCOMMANDS and flags are: obtain, install, and renew certificates: (default) run Obtain & install a certificate in your current webserver certonly Obtain or renew a certificate, but do not install it renew Renew all previously obtained certificates that are near expiry enhance Add security enhancements to your existing configuration -d DOMAINS Comma-separated list of domains to obtain a certificate for (the certbot apache plugin is not installed) --standalone Run a standalone webserver for authentication (the certbot nginx plugin is not installed) --webroot Place files in a server‘s webroot folder for authentication --manual Obtain certificates interactively, or using shell script hooks -n Run non-interactively --test-cert Obtain a test certificate from a staging server --dry-run Test "renew" or "certonly" without saving any certificates to disk manage certificates: certificates Display information about certificates you have from Certbot revoke Revoke a certificate (supply --cert-name or --cert-path) delete Delete a certificate (supply --cert-name) manage your account: register Create an ACME account unregister Deactivate an ACME account update_account Update an ACME account --agree-tos Agree to the ACME server‘s Subscriber Agreement -m EMAIL Email address for important account notifications More detailed help: -h, --help [TOPIC] print this message, or detailed help on a topic; the available TOPICS are: all, automation, commands, paths, security, testing, or any of the subcommands or plugins (certonly, renew, install, register, nginx, apache, standalone, webroot, etc.) -h all print a detailed help page including all topics --version print the version number - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certbot获取争取有好几种方式,主要就是验证域名是不是你的。
一种就是在你的站点下放一个/.well-known/acme-challenge,在里面创建一个文件然后let‘s encrypt会去请求整个文件,这种方式就是官网的Webroot的方式
第二种:就是通过DNS的查找方式取验证,具体我就不知道了,我看到有个大佬用这种方式成功了(https://soulteary.com/2018/08/30/use-docker-certbot-to-obtain-ssl-certificates.html)括号里就是大佬的链接,有兴趣可以试试,我说说我用这种方式遇到的坑。
开始我对这种方式也很感兴趣,因为看文档说这事唯一方式去获取通配符域名的证书,官方文档提供了很多DNS的插件(https://certbot.eff.org/docs/using.html#dns-plugins),我按博客里的选择了cloudflare(文档地址:https://certbot-dns-cloudflare.readthedocs.io/en/stable/),他会让你去他的网址注册账号,然后验证你的域名,这个过程说实话我觉得还是比较漫长的,最后还不知道要加什么,我是没成功,算了放弃了。所以最后我又回到了第一种方式,至于官网上的其他什么Nginx、Standalone等等我就没实践了。反正第一种方式(也就是webroot)我走通了,本来我主要就是实践,解决问题,并不计划进行科研
webroot方式因为要访问你的站点目录,所以certbot的容器呀开放站点目录的读写权限,当然首先容器肯定要映射站点目录,执行docker的命令如下
docker run -it --rm -v /home/docker-nginx/certs/www.xxx.com:/etc/letsencrypt -v /home/docker-nginx/certs/www.xxx.com:/var/lib/letsencrypt \-v /home/docker-nginx/certs/www.xxx.com:/var/log/letsencrypt \-v /home/docker-app/webapp/app:/data/letsencrypt \certbot/certbot certonly --webroot --agree-tos --webroot-path=/data/letsencrypt -m [email protected] -d www.xxx.com
解释一下
--rm,容器执行完以后删除
-v 映射容器目录
前三个主要映射证书的存储路径,因为官方文档说明了证书存储在容器里的/etc/letsencrypt目录下,为了保存证书,我所以我映射到了服务器的物理路径下。
最后一个目录就是映射我的站点目录,因为certbot验证是需要往你的站点目录写东西供他访问,所以我要做这一步。
certonly,帮助上说的很清楚了,只获取争取不安装
--webroot:验证方式使用webroot
--agree-tos:统一他的协议
--webroot-path:站点目录,这里写的是容器内的目录,要与上面映射的目录一致
-m:邮箱,说是要过期了会通知到该邮箱
-d 域名,如果有多个域名,好像说是可以接多个-d,我没试过。
第一次执行会咨询你是否确定什么的,具体忘记,反正输入一个Y就行了
说一下我在这里遇到的坑,前面说我准备了三个域名,www.xxx.com,api.xxx.com,admin.xxx.com,其中www和admin两个域名我是放静态文件的,api是我的接口站点使用asp.netcore写的webapi,www和admin我使用的就是Nginx做web服务器。api就只官网的方式,然后对外使用一个Nginx就分流。前两个www和admin获取证书都没有问题,另一个api验证失败,错误信息大概就是请求我api站点目录下的/.well-known/acme-challenge下的文件404。所以我开始怀疑是不是没有权限写,但是我检查了我整个wwwroot目录,甚至我把权限改成了777都没有效果,找不到原因。
没办法,只能想办法绕过去。后面想到,既然nginx的证书没问题,干脆我用分流的Nginx来验证我的api,然后我就在我的分流Nginx目录下放建了一个目录。修改Nginx关于api的配置
server { listen 80; #监听端口 listen 443 ssl; server_name api.xxxx.top; location ~/.well-known/acme-challenge/ { root /home/app; } #默认请求设置 location / { proxy_pass http://webapi; #转向.netcore处理 proxy_set_header Host $proxy_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Via "nginx"; } }
主要没加什么,添加了一个location,把所有有/.well-known/acme-challenge/的请求都转到/root/app上去,主语两个location的顺序,然后在Nginx容器的目录映射到物理主机上然后再执行命令
docker run -it --rm -v /home/docker-nginx/certs/api.xxx.com :/etc/letsencrypt -v /home/docker-nginx/certs/api.xxx.com :/var/lib/letsencrypt -v /home/docker-nginx/certs/api.xxx.com :/var/log/letsencrypt -v /home/docker-nginx/rootd:/data/letsencrypt certbot/certbot certonly --webroot --agree-tos --webroot-path=/data/letsencrypt -m -d api.xxx.com
看到成功的那一刻,内心真的无比激动。
证书已经获取到对应的目录下了,然后就是配置对应的站点证书了。
贴一个server就行了,其他配置都一模一样的。
server { listen 80; listen 443 ssl; server_name www.wenwangjiegua.top; ssl_certificate /home/certs/www.xxx.com/live/www.xxx.com/fullchain.pem; #证书里面,必须是包含两套完整的-----BEGIN CERTIFICATE-----和-----END CERTIFICATE----- ssl_certificate_key /home/certswww.xxx.com/live/www.xxx.com/privkey.pem; #证书密钥文件 location / { proxy_set_header Host $proxy_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Via "nginx"; proxy_pass http://webapp; #转向.netcore处理 } }
这个配置是同时存在http和https请求,Nginx的302跳转百度一下就行了。
说一下我在这步犯下的一个错误,记录一下,这里我犯了一个错误,我上面的配置都完成了,但是一直用https请求都不成功,找了半天,发现原来的我的Nginx的docker没有对外开放443端口,打开就好了。这个问题真的是查了半天。傻逼了,傻逼了。