├── hosts ├── jd └── tx ├── sites ├── cn.conf ├── route.conf └── wild.conf ├── cert.sh ├── .gitlab-ci.yml ├── s3.sh ├── deploy.sh └── README.md /hosts/jd: -------------------------------------------------------------------------------- 1 | DIRS=(cn) 2 | REMOTE_CMD="systemctl reload nginx || systemctl restart nginx" 3 | -------------------------------------------------------------------------------- /hosts/tx: -------------------------------------------------------------------------------- 1 | DIRS=(minor cn route) 2 | REMOTE_CMD="systemctl reload nginx || systemctl restart nginx" 3 | -------------------------------------------------------------------------------- /sites/cn.conf: -------------------------------------------------------------------------------- 1 | DIR="cn.xdty.org" 2 | DOMAIN="xdty.org" 3 | CERT_DOMAINS="*.cn.xdty.org xdty.org *.xdty.org > $DIR" 4 | -------------------------------------------------------------------------------- /sites/route.conf: -------------------------------------------------------------------------------- 1 | DIR="route.xdty.org" 2 | 3 | DOMAIN="xdty.org" 4 | CERT_DOMAINS="*.route.xdty.org *.xdty.org > $DIR" 5 | 6 | -------------------------------------------------------------------------------- /sites/wild.conf: -------------------------------------------------------------------------------- 1 | DIR="wild.web.xdty.org" 2 | 3 | DOMAIN="xdty.org" 4 | CERT_DOMAINS="*.web.xdty.org *.xdty.org > $DIR" 5 | ECC=TRUE 6 | 7 | -------------------------------------------------------------------------------- /cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export ALWAYS_CREATE_DOMAIN=true 4 | 5 | wget https://github.com/xdtianyu/scripts/raw/master/le-dns/le-cloudflare.sh 6 | chmod +x le-cloudflare.sh 7 | 8 | cd sites 9 | 10 | for file in ./*.conf ;do 11 | ../le-cloudflare.sh "$file"; 12 | done 13 | 14 | mv certs ../ 15 | mv accounts ../certs 16 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: alpine 2 | 3 | before_script: 4 | - apk update && apk add openssh-client bash curl wget openssl 5 | - eval $(ssh-agent) 6 | - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null 7 | 8 | stages: 9 | - build 10 | 11 | build: 12 | stage: build 13 | script: 14 | - bash s3.sh certs certs.tar.gz -d > certs.tar.gz 15 | - tar xzf certs.tar.gz || true 16 | - mv certs/accounts sites || true 17 | - mv certs sites || true 18 | - rm certs.tar.gz 19 | - bash cert.sh 20 | - bash deploy.sh 21 | - tar czf certs.tar.gz certs 22 | - bash s3.sh certs certs.tar.gz 23 | artifacts: 24 | expire_in: 1 day 25 | paths: 26 | - "certs" 27 | -------------------------------------------------------------------------------- /s3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | bucket="$1" 4 | file="$2" 5 | resource="/${bucket}/${file}" 6 | contentType="text/plain" 7 | dateValue="$(LC_ALL=C date -u +"%a, %d %b %Y %X %z")" 8 | 9 | if [ "$3" == "-d" ]; then 10 | PARAMS="" 11 | stringToSign="GET\n\n${contentType}\n${dateValue}\n${resource}" 12 | else 13 | PARAMS="-X PUT -T ${file}" 14 | stringToSign="PUT\n\n${contentType}\n${dateValue}\n${resource}" 15 | fi 16 | 17 | signature=`echo -en ${stringToSign} | openssl sha1 -hmac ${MINIO_SECRET_KEY} -binary | base64` 18 | 19 | curl -k ${PARAMS} \ 20 | -H "Date: ${dateValue}" \ 21 | -H "Content-Type: ${contentType}" \ 22 | -H "Authorization: AWS ${MINIO_ACCESS_KEY}:${signature}" \ 23 | $S3_URL/${bucket}/${file} 24 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p ~/.ssh 4 | chmod 700 ~/.ssh 5 | 6 | wget $KEYS_URL/config -O ~/.ssh/config 7 | wget $KEYS_URL/known_hosts -O ~/.ssh/known_hosts 8 | 9 | for file in $(find hosts -type f) ; do 10 | DIRS=() && REMOTE_CMD="" && . "$file" 11 | 12 | if [ -z "$DIRS" ]; then 13 | echo "# DIRS is not configured, ignore $file." 14 | continue 15 | fi 16 | 17 | host=$(basename $file) 18 | for conf in "${DIRS[@]}"; do 19 | DIR="" && . "sites/$conf.conf" 20 | if [ -z "$DIR" ]; then 21 | echo "# DIR is not configured, ignore $conf." 22 | continue 23 | fi 24 | echo "# $file: copy $DIR --> $host" 25 | mkdir -p dist/$host/le/certs/$DIR/ 26 | cp certs/$DIR/fullchain.pem dist/$host/le/certs/$DIR/ 27 | cp certs/$DIR/privkey.pem dist/$host/le/certs/$DIR/ 28 | done 29 | 30 | tar czf dist/$host.tar.gz -C dist/$host/ le 31 | scp dist/$host.tar.gz $host: 32 | echo "# $file: $host --> $REMOTE_CMD" 33 | ssh $host " 34 | mkdir -p /etc/nginx/ 35 | [ -e /etc/nginx/le ] && rm -r /etc/nginx/le 36 | tar xzf $host.tar.gz -C /etc/nginx/ --warning=no-timestamp 37 | rm \"$host.tar.gz\" 38 | $REMOTE_CMD 39 | " 40 | done 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Certs 2 | 3 | 利用 `Gitlab ci` 自动部署 `ssl` 证书文件 4 | 5 | ## 如何使用 6 | 7 | 只需要修改 `git repo` 中的配置文件,配置域名和目标机器的主机名 `host` 并提交就可以自动部署。 8 | 9 | ## 说明 10 | 11 | 证书文件默认会被拷贝到目标机器 `/etc/nginx/le/` 目录下,请修改 `nginx` 等服务配置的证书路径 12 | 13 | ## 准备 14 | 15 | 1. 域名托管在 cloudflare,在 ci 运行时会需要通过 dns 认证方式获取 le 证书 16 | 17 | 2. 目标机器已经添加 ci 的 ssh 公钥 `id_rsa.pub` 到 `.ssh/authorized_keys`, ci 运行时会通过 `scp` 将证书文件拷贝到 `/etc/nginx/le` 目录。 18 | 19 | 3. 一个 s3 兼容的外部存储,如自建 `minio`,用来存储 ci 生成的证书文件,这样就不需要每次生成新证书了。 ci 在运行前会先从 s3 下载证书文件,检查是否快过期,如果不需要更新证书就会使用已有的证书文件。 20 | 21 | 4. ssh 客户端 `.ssh/config` 和 `.ssh/know_hosts` 文件并可以通过 HTTP 下载,配置好目标机器的 ssh 地址和端口 如 22 | 23 | ``` 24 | host example 25 | hostname example.xdty.org 26 | port 22 27 | user root 28 | ``` 29 | 30 | ## 配置 31 | 32 | 1. 添加域名 33 | 34 | 在 `sites/` 目录下增加 `your_site.conf` 配置文件,如 `wild.conf`,添加类似如下内容 35 | 36 | ``` 37 | DIR="wild.web.xdty.org" 38 | DOMAIN="xdty.org" 39 | CERT_DOMAINS="xdty.org *.xdty.org *.web.xdty.org > $DIR" 40 | #ECC=true 41 | ``` 42 | 其中 `DIR` 为证书生成的目录,`DOMAIN` 是域名,`CERT_DOMAINS` 是证书配置的域名,也可以增加 `ECC=true` 表示输出 `ECC` 证书。 43 | 44 | 其中 `xdty.org *.xdty.org *.web.xdty.org > $DIR` 表示指定证书到 `DIR` 目录。如果不需要多级证书,可以不显示指定目录,如下配置会直接生成证书到 `xdty.org` 目录下。 45 | 46 | ``` 47 | DIR="xdty.org" 48 | DOMAIN="xdty.org" 49 | CERT_DOMAINS="xdty.org *.xdty.org" 50 | ``` 51 | 52 | 可以在 `sites/` 下添加多个配置文件来获取多个域名的证书并生成到相应目录。 53 | 54 | 2. 添加主机 55 | 56 | 在 `hosts` 目录下添加主机配置文件,如 `jp` 配置文件 57 | 58 | ``` 59 | DIRS=(busy wild tws route) 60 | REMOTE_CMD="systemctl reload nginx || systemctl restart nginx" 61 | ``` 62 | 注意这里的配置文件名是与目标主机的 `hostname` 对应的,运行时会根据配置文件名 `scp` 到目标 `host` 63 | 64 | `DIRS` 表示向 `jp` 主机中添加 `busy wild tws route` 这四个域名的证书文件,这里的域名和 `sites/` 目录下的文件名相同,如域名配置文件名为 `wild.conf`,则对应的这里填为 `wild` 65 | 66 | `REMOTE_CMD` 表示部署完成后执行的命令,这里的命令为重新加载 nginx 服务 67 | 68 | ## CI 环境变量 69 | 70 | 需要添加如下 CI 环境变量 71 | 72 | | 环境变量 | 说明 | 73 | | ---------------- | ------------------------------------------------------------ | 74 | | CF_EMAIL | cloudflare 登陆邮箱 | 75 | | CF_TOKEN | cloudflare api token | 76 | | KEYS_URL | 外部 ssh 配置路径,用来获取 `.ssh/config` 和 `.ssh/known_hosts` 如 `https://keys.xdty.org` | 77 | | MINIO_ACCESS_KEY | 外部 s3 存储服务 access key | 78 | | MINIO_SECRET_KEY | 外部 s3 存储服务 secret key | 79 | | S3_URL | 外部 s3 存储服务 如 `https://s3.xdty.org` | 80 | | SSH_PRIVATE_KEY | CI 自动部署私匙,`id_rsa` 文本内容,与集成到目标机器的 `authorized_keys` 对应 | 81 | 82 | 83 | 84 | ---------- 85 | 86 | Automatic deployment of `ssl` certificate files with `Gitlab ci` 87 | 88 | 89 | 90 | --------------------------------------------------------------------------------