快速实现静态站点的自动化更新

在现代前后端分离或静态站点,将网站代码安全快速的推送到 Web 服务器提高效率的必由之路。

架构

开发者将网站代码 Push 到 GitLab 的主分支。GitLab CI 启动一个临时的轻量级 Runner,通过 SSH 触发 Web Server 主动拉取 Git 代码。专用的 pushgit 容器与 Nginx 容器分离,只有静态资源/代码所在的目录是共享挂载的。CI 只与 pushgit 容器通信,没有任何 Web Server 的其它权限。

Web Server 端配置与搭建

pushgit 容器

这个容器用于接受 GitLab CI 的SSH访问,触发拉取 Git 更新网站文件。

  • 生成容器中 SSHd 的主机密钥存放在 host_key 目录下,保持容器重建后的主机密钥不变
  • 生成一对用户密钥存放在 id_key 目录下,以后容器就是用这个私钥到 GitLab 上拉取文件
  • authorized_keys 存放的是 GitLab CI 的 SSH 公钥,CI 用这个公钥来触发更新

docker-compose.yml:

  pushgit:
    build: ./pushgit
    image: pushgit
    container_name: pushgit
    restart: unless-stopped
    ports:
      - 2222:22
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - ./yaoge1:/var/www/yaoge1:rw
      - ./yaoge2:/var/www/yaoge2:rw

Dockerfile:

FROM alpine:latest

RUN sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.cernet.edu.cn/alpine#g' /etc/apk/repositories

RUN apk update --no-cache \
 && apk upgrade --no-cache \
 && apk add --no-cache tzdata ca-certificates openssh-server openssh-client git \
 && update-ca-certificates \
 && rm -rf /var/cache/apk/*

COPY --chmod=0600 host_key/ssh_host_*_key /etc/ssh/
COPY --chmod=0644 host_key/ssh_host_*_key.pub /etc/ssh/
RUN echo "PasswordAuthentication no" > /etc/ssh/sshd_config.d/disable_password.conf \
 && echo "StrictHostKeyChecking accept-new" > /etc/ssh/ssh_config.d/accept_hostkey.conf

RUN adduser -D -u 1000 -h /home/pushgit -s /home/pushgit/pushgit.sh pushgit && passwd -u pushgit
COPY --chown=pushgit:pushgit --chmod=0700 pushgit.sh /home/pushgit/
RUN install -d -m 0700 -o pushgit -g pushgit /home/pushgit/.ssh
COPY --chown=pushgit:pushgit --chmod=0600 id_key/id_* /home/pushgit/.ssh/
COPY --chown=pushgit:pushgit --chmod=0600 authorized_keys /home/pushgit/.ssh/
RUN ssh-keyscan git.yaoge123.com >> /home/pushgit/.ssh/known_hosts \
 && chown pushgit:pushgit /home/pushgit/.ssh/known_hosts \
 && chmod 0644 /home/pushgit/.ssh/known_hosts

CMD ["/usr/sbin/sshd", "-De"]

pushgit.sh:

#!/bin/sh
set -e
echo "$2: "
cd "/var/www/$2" || { echo "Directory not found!"; exit 1; }
git config --global safe.directory "/var/www/$2"
git fetch --all
git reset --hard @{upstream}
git clean -fd

authorized_keys:

restrict,command="yaoge1" ssh-ed25519 AxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxZ gitlab-yaoge1
restrict,command="yaoge2" ssh-ed25519 AxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxU gitlab-yaoge2

Nginx 配置

server {
    listen 80;
    listen [::]:80;
    server_name yaoge1.yaoge123.com;
    server_tokens off;
    return 301 https://$server_name$request_uri;
}

server {
    listen *:443 ssl;
    listen [::]:443 ssl;
    server_name yaoge1.yaoge123.com;
    server_tokens off;
    
    include ssl/acme-challenge.conf;
    include ssl/yaoge123_com.conf;

    location ~ /\.git {
        return 404;
    }

    root /var/www/yaoge1;
}

GitLab 端配置

创建一个用户(比如 WebServerPush),把上述 id_key/id_*.pub 加入用户的 SSH Keys 下,把这个用户加入到项目成员中,给 Reporter 角色。这个用户是公用的,所有类似的项目都添加这个用户即可。

生成一对网站项目专用的 key,其中公钥放到上述 authorized_keys 中,私钥经BASE64编码后存到CI/CD变量中。

变量键值 (Key)说明
SSH_PRIVATE_KEY_BASE64SSH 私钥的Base64编码,选择 Masked and hidden 和 Protect variable
SERVER_IPWeb Server 的 IP
SERVER_PORTpushgit 容器暴露的 SSH 端口(如上文示例的 2222)
SSH_USERpushgit 容器内的操作账户(如上文示例的 pushgit)

.gitlab-ci.yml

deploy_to_server:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client coreutils
    - echo "$SSH_PRIVATE_KEY_BASE64" | base64 -d > ./ssh_key
    - chmod 400 ./ssh_key
  script:
    - ssh -o StrictHostKeyChecking=accept-new -i ./ssh_key -T -p $SERVER_PORT $SSH_USER@$SERVER_IP

下面只要在 Web Server 上用 git clone 初始化一下即可,后续只要 git 推送了新的文件,就会自动触发更新。

廉价SSL证书比较

  首先是当然推荐免费的Let’s Encrypt,支持ECDSA和泛域名,极大地推动了HTTPS的普及,但是90天的有效期太短了。对于复杂的系统来说,会有很多不能自动导入证书的设备,管理起来成本太高。因此我们来看一下三种便宜的SSL证书:Sectigo (Comodo)、RapidSSL、AlphaSSL。

  Sectigo(原Comodo,拆分出售后改名),主品牌一直以来就是廉价SSL证书的代表,所以用它家证书的基本都是小网站。Comodo自己拥有四个根证书,分别是COMODO RSA Certification AuthorityCOMODO ECC Certification AuthorityUSERTrust RSA Certification AuthorityUSERTrust ECC Certification Authority,都是从2010年(COMODO ECC从2008年起)起至2038年止的根证书,这四个证书比较新故在老的系统中不受信任,不过也因为比较新所以提供了更高的安全性并且完美支持ECDSA(RSA4096、ECC384,SHA384)。对于老的系统,COMODO收购了一个从2000年起的根AddTrust External CA Root,但是这个证书到2020年5月30日就过期了,不过COMODO还有一个2004年起的根AAA Certificate Services能一直用到2028年。AddTrust和AAA在老系统中兼容性很好,只要在服务器的证书链中导入交叉签名的第二个中级证书即可,这样老系统就能信任新颁发的SSL证书,但是这样会导致证书链变长(两个中级证书)。Sectigo的证书几乎所有网站都在卖,最便宜的通配符证书应该是GoGetSSL售卖的自有品牌证书(4年$32.5/year),Sectigo用自己的根证书给GoGetSSL签发了两个中级证书GoGetSSL RSA DV CAGoGetSSL ECC DV CA,GoGetSSL再用自己的中级证书给用户签发SSL证书,所以和Sectigo证书兼容性一样。

  RapidSSL是DigiCert下属的廉价证书品牌,使用DigiCert的根证书,根和中级证书只支持RSA。RapidSSL比较有名,很多网站都有转售,通配符证书两年期SSL2BUY便宜(2年$73.5/year),四年期CheapSSLsecurity更便宜一点(4年$72.31/year)。

  AlphaSSL是GlobalSign下属的廉价证书品牌,使用GlobalSign的根证书,根和中级证书只支持RSA。这个名气小很多,很少有网站转售,通配符证书两年期SSL2BUY便宜(2年$40/year)。

  综上所述,想要便宜且整个证书链支持ECDSA只能买GoGetSSL,但是对于老终端需要四级证书链。不需要整个证书链是ECDSA的,老终端也只有一个中级证书的三级证书链,可选RapidSSL和AlphaSSL,RapidSSL名气大一点,其它的基本没有区别。

  现在几乎所有的SSL证书都是由中级证书签发的,而直接由根证书签发没有中级证书的SSL证书现在应该已经不存在了,因为这样根证书太不安全了。所以三级证书链基本上就是最短的证书链了。多一级中级证书服务器额外发送大约2K的证书信息,客户端需要多查询一个证书的吊销情况。

CAs trustworthy in browsers db可以大概查看各个根证书受信任情况。

批量更改Transmission的tracker

某些站会改tracker,所以需要批量更改已有种子的tracker

#!/bin/bash

username="yaoge123"
password="yaoge123"
host="localhost:9091"

for i in $(transmission-remote $host -n $username:$password -l|awk '{print $1}'|grep -o -P '\d+')
do
	out=$(transmission-remote $host -n $username:$password -t $i -it|grep $1)
	if [ -n "$out" ];then
		id=$(echo "$out"|awk -F: '{print $1}'|grep -o -P '\d+')
		echo $i
		transmission-remote $host -n $username:$password -t $i -tr $id
		transmission-remote $host -n $username:$password -t $i -td $2
	fi
done

用法:./chtracker.sh https://old.tracker.com https://new.tracker.com/announce.php?passkey=xxxxxxxxxx

通配符SSL证书

域名验证通配符证书主要有:
GeoTrust RapidSSL Wildcard
Comodo PositiveSSL Wildcard
Comodo EssentialSSL Wildcard
GlobalSign AlphaSSL Wildcard

兼容性:GeoTrust>Comodo>GlobalSign

市场占用率文章:http://w3techs.com/technologies/overview/ssl_certificate/all

基本上最高端兼容性最好的CA都在Symantec手里了

Apache 配置SSL

SSLEngine on
SSLProtocol all -SSLv2 //只允许SSLv3和TLSv1,SSLv2有缺陷禁止掉
SSLCipherSuite RSA:DH:DSS:!EXP:!NULL:!ADH:!EDH:!LOW:!RC4:!MD5:HIGH:MEDIUM //最终的结果就是Key Exchange=RSA/DH,Authentication=RSA/DSS,Cipher Encoding=AES(128/256)/3DES(168),MAC Digest=SHA1
SSLCertificateFile /etc/ssl/certs/nnlm.cer //CA颁发的证书
SSLCertificateKeyFile /etc/ssl/private/nnlm.key //证书的私钥
SSLCertificateChainFile /etc/ssl/certs/chain.cer //证书链,所有的证书链全部写到一个文件里面

网易、搜狐、QQ之企业邮箱对比

用户数和客户端支持:
网易:200个,用满后可申请扩容(人工审核要求较高),支持POP3/SMTP。
搜狐:个人100、企业200,需要上传证件才能使用POP3/SMTP。
QQ:200个,可以通过邀请其他人用QQ企业邮箱增加到最多500个,支持POP3/SMTP/IMAP。

邮箱容量:
网易:3GB。
搜狐:2GB。
QQ:无限。

用户分组:
网易:支持。
搜狐:不支持。
QQ:支持多级分组。

SSL:
网易:登陆时可选SSL,进入后非SSL,不过证书是CNNIIC签发的:(
搜狐:不提供SSL。
QQ:全程SSL,POP3/SMTP/IMAP也支持SSL,证书Equifax颁发。

二级域名:
网易:不支持。
搜狐:支持。
QQ:支持。

后台管理:
网易:用户管理,管理日志。
搜狐:用户管理,管理日志,用户使用空间和发信数量统计。
QQ:用户管理,管理日志,用户发信统计和日志,分级管理员,错误地址转发。

特点:
搜狐:会话式邮件,邮件全文搜索
QQ:企业网盘