起因
-
原先一直有一个腾讯云的1核和1G的服务器在闲着,只是偶尔用下frp
来映射开发演示,这次想再利用下,于是试下搭建bitwarden
,转而找到更加小巧的vaultwarden
,但实际浏览器插件测试必须是要https
才行,所以必须要有域名及证书,顺便就想试下certbot
来自动续签。
-
域名随便在阿里云上弄了个top
的,10年¥189,要想解析到服务器是要备案的,所以又在腾讯云上备案,大约有7、8个工作日吧,备案才通过,此时可以正常访问了,然后还要30日内进行公安备案。
-
由于服务器上的nginx
、frp
、vaultwarden
都是docker
来部署的,那certbot
也顺便就用docker
,官方虽然提供了docker
镜像,但实际上并不是很推荐使用,因为容器内比较难触发外部的一些操作,会导致一些自动配置的功能很难使用,参考官方文档:Running with Docker。
certbot
发放证书前需要验证域名的合法性,确保你申请证书的域名是你的,验证方式主要分两种:
certbot
的命令有很多种不同的参数,这些参数也主要是为了自动生成http验证文件或自动添加dns解析等功能,主要的大体说下:
-
--manual
,手动配置,你可以自己选择http验证还是dns验证都行,需要自己纯手工去配置http验证文件或是dns解析,个人没有做测试。
-
--nginx
,走http验证,如果不用docker
且用nginx感觉是最方便的,会自动修改nginx的配置文件,增加http请求的访问配置及后续的ssl配置,但由于我们certbot
是在docker
容器内,所以要修改另一个nginx
容器的配置文件及控制启停不太好实现,所以不采用这种方式。查资料时发现有人会将nginx
和 certbot
通过dockerfile
打包到一个镜像内,这样此命令就比较方便的执行了,感觉是个好办法,但个人没有测试了解。
-
--dns-xxx
,走dns解析验证,这个也很方便,配置好后会自动在域名解析中增加一条记录进行域名验证,但官方目前只支持国外的一些dns服务商,国内的阿里云、dnspod等貌似也有第三方的插件,可以自己去github
上找下,目前个人没有测试。
-
--standalone
,走http验证,这种方式你就算是没有nginx
等服务,仍然可以验证域名并获取证书,它会虚拟一个服务来进行验证,但需要保证你的80
端口别被占用,由于我这边有nginx
了,所以便没有用此类方法测试。
-
--webroot
,走http验证,已有类似nginx等服务的情况下可以用此方法,会自动在你配置的目录下生成http验证文件,与standalone
相比好处是不需要预留80端口,也就是原有的网站不需要停止就可以申请证书,而缺点就是你还需要在nginx
等服务中手动配置/.well-known/acme-challenge/
使其对应到自动生成的验证文件上。后续我们用的就是这种。
通过webroot
的方式运行后,会在两个地方产生文件:
以上两个文件虽然是certbot
容器生成的,但我们nginx
容器都会用到,所以我们需要用宿主机做为中转,在certbot
和nginx
容器中都配置映射到宿主机的同一个目录,从而实现certbot
容器和nginx
容器共用文件。我的服务器home/ubuntu/docker
下的目录可参照:
├── certbot
│ ├── ssl //存放证书
│ └── www //存放http验证的临时文件
├── nginx
│ ├── conf
│ │ └── conf.d //配置文件
│ │ └── valtwarden.conf //配置文件
│ ├── log //日志
│ └── web //存放网站
└── docker-compose.yml //docker-compse文件
准备
开始
-
主要是把volume
映射弄好,顺便配置好nginx
的相关http验证:
-
docker-compose.yml:
version: "3.9"
services:
nginx:
container_name: nginx
image: nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
TZ : 'Asia/Shanghai'
volumes:
- /home/ubuntu/docker/nginx/conf:/etc/nginx # 配置文件
- /home/ubuntu/docker/nginx/web:/usr/share/nginx # 网站
- /home/ubuntu/docker/nginx/log:/var/log/nginx #日志
- /home/ubuntu/docker/certbot/www:/usr/share/certbot/www:ro #http验证目录,可设置ro为只读,因为文件最终时通过certbot容器映射来的
- /home/ubuntu/docker/certbot/ssl:/usr/share/certbot/ssl:ro #证书位置,同上
command: nginx -g 'daemon off;'
certbot:
container_name: certbot
image: certbot/certbot
volumes:
- /home/ubuntu/docker/certbot/www:/usr/share/certbot/www:rw #http验证目录,可设置rw可写,与nginx容器对应的宿主机目录时一致的
- /home/ubuntu/docker/certbot/ssl:/etc/letsencrypt:rw #证书位置,同上,注意不要只映射到live,而是它的上一级
-
nginx配置valtwarden.conf:
server {
listen 80;
listen [::]:80;
server_name bitwarden.xxx.top;#域名
server_tokens off;
#配置http验证可访问
location /.well-known/acme-challenge/ {
#此目录都是nginx容器内的目录,对应宿主机volumes中的http验证目录,而宿主机的又与certbot容器中命令--webroot-path指定目录一致,从而就整个串起来了,解决了http验证问题
root /usr/share/certbot/www;
}
#http跳转到https
location / {
return 301 https://bitwarden.xxx.top$request_uri;
}
}
-
上方的volumes映射串联关系如下,通过宿主机来实现certbot
和nginx
中相关的目录实际上是同一个目录,除了certbot
中的/etc/letsencrypt
是固定的外,其余的目录都是可以随便找目录放,只要对应起来就行。
目录 |
certbot |
宿主机 |
nginx |
http验证目录 |
/usr/share/certbot/www |
/home/ubuntu/docker/certbot/www |
/usr/share/certbot/www |
证书目录 |
/etc/letsencrypt |
/home/ubuntu/docker/certbot/ssl |
/usr/share/certbot/ssl |
-
docker-compose up -d nginx
先把nginx开启,然后测试证书发放是否可以:
# --dry-run是只测试不实际生成; --webroot-path对应着certbot内的http验证目录;-d后面是域名;--rm是运行后接着删除,certbot容器不需要一直开启,只是启动下生成证书即可
docker-compose run --rm certbot certonly --webroot --webroot-path /usr/share/certbot/www/ --dry-run -d bitwarden.xxx.top
-
输入邮箱等信息,如果提示The dry run was successful
则说明成功,可以去掉--dry-run
参数来进行实际的获取证书
docker-compose run --rm certbot certonly --webroot --webroot-path /usr/share/certbot/www/ -d bitwarden.xxx.top
-
如果上方正常,则会在certbot
容器下的/etc/letsencrypt
下也就是nginx
容器下的/usr/share/certbot/ssl
下产生证书,此时,只需要配置nginx配置ssl即可,还是在文件valtwarden.conf中:
server {
listen 80;
listen [::]:80;
server_name bitwarden.xxx.top;#域名
server_tokens off;
#配置http验证可访问
location /.well-known/acme-challenge/ {
#此目录都是nginx容器内的目录,对应宿主机volumes中的http验证目录,而宿主机的又与certbot容器中命令--webroot-path指定目录一致,从而就整个串起来了,解决了http验证问题
root /usr/share/certbot/www;
}
#http跳转到https
location / {
return 301 https://bitwarden.xxx.top$request_uri;
}
}
#ssl配置
server {
listen 443 ssl;
server_name bitwarden.xxx.top;
#日志
access_log /var/log/nginx/bitwarden.access.log main;
error_log /var/log/nginx/bitwarden.error.log;
#证书信息,这里的路径是nginx容器内的
ssl_certificate /usr/share/certbot/ssl/live/bitwarden.xxx.top/fullchain.pem;
ssl_certificate_key /usr/share/certbot/ssl/live/bitwarden.xxx.top/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://vaultwarden;#这里是代理到valutwarden容器上了
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
-
以上docker-compose exec nginx nginx -t
检测配置nginx文件是否有问题,docker-compose exec nginx nginx -s reload
或者是直接docker-compose restart nginx
来重启nginx
-
正常启动的话应该就没问题了,我们接着需要做定期更新证书,主要就是为了这个,否则直接腾讯云、阿里云申请一年的免费证书好了。增加计划任务, sudo crontab -e
打开定时任务编辑,每月1号和15号运行一次
#1、切换到docker-compose.yml所在目录;2、然后更新证书,只有距离过期时间30天内才会真正成功;3、然后重载nginx使新证书生效
0 0 1,15 * * root cd /home/ubuntu/docker && /usr/local/bin/docker-compose run --rm certbot renew && /usr/local/bin/docker-compose exec nginx nginx -s reload
以上是计划任务相关,目前我也是刚部署,还没看到实际效果,不一定正确。certbot
容器中renew
虽然有--deploy-hook
等实际更新后触发钩子的功能,但由于和nginx
不在同一个容器,因此无法触发nginx重启,所以上述命令不管是否证书真正更新成功nginx是一定会重启的,最好放到深夜执行。搜索了下从一个容器中控制另一个容器的操作,一种是本容器内装docker,然后映射宿主机内的docker.sock,这样容器内操作docker就和宿主机内操作一致了;还有一种就是ssh来连接另一个容器来操作了,这两种都挺麻烦的,这里就没必要也不做尝试了。
其它