准备把我的博客放在容器中,由于我的博客使用了 let’s encrypt,我希望把他也加入到容器中实现自动签发证书的自动化功能。不过在这个过程中我遇到了很多问题,现在就遇到的问题进行一些小小的总结。
签名错误
首先,遇到的第一个问题就是当执行 docker build 时 总是会卡在下载 acme.sh 认证这步,报错
Specified signature is not matched with our calculation. server string to sign ....
谷歌一番发现这个是阿里云的 API 报的错误,签名有问题,可是我在本地测试是 OK 的啊。肯定是少了什么东西,检查一番发现是容器内的时间是 UTC 的 要比 GMT 的时间少8小时。于是要解决这个办法就是在 dockerfile 中加入一句
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
这样就不会有问题了。
下载 acme.sh 出错
在我一开始之间使用以下命令去下载 acme.sh 时总是会build 失败
RUN wget -O - https://get.acme.sh | sh
后来调整为
RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://get.acme.sh | sh"]
则没有问题,当然执行签发证书时候也需要这样写
RUN ["/bin/bash", "-c", "set -o pipefail && /root/.acme.sh/acme.sh --issue -d awen.me -d *.awen.me --dns dns_cf --keylength ec-256 --debug"]
否则可能会出现请求超时异常退出无法继续 build。
too many certificates already issued for exact set of domains
在申请证书时候,我们需要加上 –debug,否则如果出现异常我们无法判断是哪里出了问题
/root/.acme.sh/acme.sh --issue -d awen.me -d *.awen.me --dns dns_cf --keylength ec-256 --debug
当开启 debug 后,build 镜像提示
[Tue Jun 19 22:44:33 CST 2018] {"type":"urn:ietf:params:acme:error:rateLimited","detail":"Error finalizing order :: too many certificates already issued for exact set of domains: *.awen.me,awen.me: see https://letsencrypt.org/docs/rate-limits/","status": 429}
[Tue Jun 19 22:44:33 CST 2018] _on_issue_err
[Tue Jun 19 22:44:33 CST 2018] Please add '--debug' or '--log' to check more details.
[Tue Jun 19 22:44:33 CST 2018] See: https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh
[Tue Jun 19 22:44:33 CST 2018] socat doesn't exists.
[Tue Jun 19 22:44:33 CST 2018] Diagnosis versions:
openssl:openssl
OpenSSL 1.0.1t 3 May 2016
apache:
apache doesn't exists.
nginx:
nginx doesn't exists.
socat:
The command '/bin/bash -c set -o pipefail && /root/.acme.sh/acme.sh --issue -d awen.me -d *.awen.me --dns dns_cf --keylength ec-256 --debug' returned a non-zero code: 1
说明这个域名申请证书的次数过多了,你可以通过这个crt.sh是查看你的域名的申请次数,一般来说如果出现这个错误需要距离上次申请的日期顺延7天才可以。
为了减少每次 build 都去申请一次导致次数过多,可以先在本地申请,然后将本地的 /.acme.sh 目录下的证书目录拷贝过去以及保存 API 信息的 account.conf 文件拷贝到容器的/.acme.sh 目录下,这样后期只需要校验证书是否过期即可。
RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://get.acme.sh | sh"]
COPY account.conf /root/.acme.sh/account.conf
COPY awen.me_ecc /root/.acme.sh/awen.me_ecc
计划任务
在安装 acme.sh 程序时如果没有安装 cron,则无法运行。安装 cron 很简单,类似下面这样
COPY crontab /var/spool/cron/crontabs/root
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
apt-get update && \
apt-get install build-essential libpcre3 libpcre3-dev zlib1g-dev wget libtool automake openssh-server supervisor cron -y && \
……
chown -R root:crontab /var/spool/cron/crontabs/root && \
chmod 600 /var/spool/cron/crontabs/root && \
touch /var/log/cron.log
使容器保持运行状态
可以使用 supervisord ,安装
apt-get install supervisor
supervisord.conf 配置
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
[program:nginx]
command=/etc/init.d/nginx start
[program:crontab]
command=/etc/init.d/cron start
然后在dockerfile 中加入
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
acme.sh 无法验证
可以在本地先执行一遍,然后将/.acme.sh/account.conf 拷贝到容器的/.acme.sh/ 下
COPY account.conf /root/.acme.sh/account.conf
完整的 dockerfile 文件参考
FROM debian:jessie
MAINTAINER NGINX Docker Maintainers "hi@awen.me"
WORKDIR /opt
ENV DIR="/opt/nginx/" \
ZLIB="zlib-1.2.11.tar.gz" \
ZLIB_DIR="zlib-1.2.11" \
PCRE="pcre-8.41.tar.gz" \
PCRE_DIR="pcre-8.41" \
OPENSSL="openssl-1.0.2o.tar.gz" \
OPENSSL_DIR="openssl-1.0.2o" \
NGINX="nginx-1.14.0.tar.gz" \
NGINX_DIR="nginx-1.14.0" \
NGX_BROTLI="ngx_brotli"
COPY sources.list.jessie /etc/apt/sources.list
COPY nginx.sh /etc/init.d/nginx
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
apt-get update && \
apt-get install build-essential libpcre3 libpcre3-dev zlib1g-dev wget libtool automake openssh-server supervisor cron rsync -y && \
mkdir -p /opt/nginx && \
cd $DIR && \
wget -c -4 http://zlib.net/$ZLIB -O $DIR$ZLIB && \
tar zxvf $ZLIB && \
cd $ZLIB_DIR && \
./configure && \
make && \
make install && \
cd $DIR && \
wget -c -4 https://ftp.pcre.org/pub/pcre/$PCRE -O $DIR$PCRE && \
tar zxvf $PCRE && \
cd $PCRE_DIR && \
./configure && \
make && \
make install && \
cd $DIR && \
wget -c -4 https://www.openssl.org/source/$OPENSSL -O $DIR$OPENSSL && \
tar zxvf $OPENSSL && \
groupadd www && \
useradd -s /sbin/nologin -g www www && \
cd $DIR && \
wget -c http://file201503.oss-cn-shanghai.aliyuncs.com/awen/ngx_brotli.tar.gz && \
tar zxvf ngx_brotli.tar.gz && \
wget -c -4 https://nginx.org/download/$NGINX -O $DIR$NGINX && \
tar zxvf $NGINX && \
cd $NGINX_DIR && \
./configure --prefix=/usr/local/nginx --user=www --group=www --with-pcre=$DIR$PCRE_DIR --with-http_v2_module --with-http_ssl_module --with-zlib=$DIR$ZLIB_DIR --with-openssl=$DIR$OPENSSL_DIR --add-module=$DIR$NGX_BROTLI && \
make && \
make install && \
rm -rf /usr/local/nginx/conf/vhost && \
mkdir /usr/local/nginx/conf/vhost && \
rm -rf /usr/local/nginx/conf/nginx && \
mkdir /usr/local/nginx/ssl && \
cd $DIR && \
mkdir -p /var/run/sshd && \
mkdir -p /var/log/supervisor && \
mkdir -p /www/www && \
mkdir -p /www/wwwlogs && \
chown -R www:www /www/ && \
rm -rf /opt/ && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
chmod +x /etc/init.d/nginx
RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://get.acme.sh | sh"] && \
chown -R root:crontab /var/spool/cron/crontabs/root && \
chmod 600 /var/spool/cron/crontabs/root && \
touch /var/log/cron.log && \
mkdir -p /root/.acme.sh/awen.me_ecc
COPY account.conf /root/.acme.sh/account.conf
COPY awen.me_ecc /root/.acme.sh/awen.me_ecc
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY awen.me.conf /usr/local/nginx/conf/vhost
COPY nginx.conf /usr/local/nginx/conf
RUN /root/.acme.sh/acme.sh --installcert -d awen.me --ecc --keypath /usr/local/nginx/ssl/awen.me.key --fullchainpath /usr/local/nginx/ssl/awen.me.cer --reloadcmd "/etc/init.d/nginx restart"
EXPOSE 22 80 443
VOLUME ["/www/www","/www/wwwlogs"]
CMD ["/usr/bin/supervisord"]