Skip to main content

使用Let's Encrypt不花钱打造A+级SSL站点

· 6 min read

有这样一个组织为了推动整个互联网环境的安全,免费提供跟你网站域名匹配的并且被各大浏览器信任的 SSL 证书,这个组织的名称叫做 ISRG -- Internet Security Research Group,ISGR 提供了一个服务叫 Let's Encrypt (https://letsencrypt.org),网民们可以方便的使用该网站免费创建属于自己的 SSL 证书。并且 ISGR 允许免费创建泛域名 SSL 证书。

下面就来说说怎样使用 Let's Encrypt 提供的服务免费创建泛域名证书。

假设场景:

  • 小张注册了一个域名:example.com
  • 小张想建一个网站,域名为 www.example.com 和 example.com
  • 小张又想建一个博客,域名为 blog.example.com
  • 小张又想建一个论坛,域名为 forum.example.com
  • 以上网址都以 HTTPS 的方式访问
  • 环境: CentOS 7 + Nginx 1.13
  • 工具: openssl, https://www.sslforfree.com

一个支持多域名的证书可以满足上述需求,该证书需要绑定两个域名 example.com 和*.example.com, 下面详表过程:

一、创建 Private Key(私钥)

关系到数据安装的一个 Key, 千万不能泄漏。使用 openssl 生成 2048 位私钥,输出文件名为 example.com.key:

# openssl genrsa -out example.com.key 2048

二、为绑定多域名创建配置文件

从/etc/pki/tls/openssl.cnf 复制一个文件 example.com.cnf

# cp /etc/pki/tls/openssl.cnf example.com.cnf

修改 example.com.cnf:

1. 找到[ req ]节中被注释掉的 req_extensions = v3_req,去除行首的#使其生效,或添加对应内容:

[ req ]
...
req_extensions = v3_req # The extensions to add to a certificate request
...

2. 找到[ v3_req ]节添加 subjectAltName,内容如下:

[ v3_req ]
subjectAltName = @alt_names

3. 添加[ alt_names ]小节,并在下面添加 DNS.1 和 DNS.2 分别等天 example.com 和*.example.com:

[ alt_names ]
DNS.1 = example.com
DNS.2 = *.example.com

保存退出编辑器。

三、使用 openssl 创建 CSR (Certificate Signing Request)文件

使用前面步骤创建的 Private Key 和 cnf 文件作为输入参数,生成 CSR, 过程中需要填写证书申请的相关信息,包括国家代码,州省,城市,证书所属组织名称,证书显示名称等,按向导依次填即可:

# openssl req -new -key example.com.key -out example.com.csr -config example.com.cnf
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Guangdong
Locality Name (eg, city) [Default City]:Shenzhen
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []: Thomas
Common Name (eg, your name or your server's hostname) []:example.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

还有一种更快捷的方法是在 cnf 文件中把所有内容填好,在向导中就只需要按回车就好了:

查验 Request 文件:

# openssl req -in example.com.csr -noout -text

四、访问 sslforfree.com,生成证书:

1. 在浏览器中输入网址:https://www.sslforfree.com, 然后在 sslforfree 的网站的域名输入框中输入 example.com *.example.com,点击 Create Free SSL Certificate 按钮继续:

2. 然后 sslforfree 网站会提示你需要验证该域名是否为你所有,点击 Manually Verify Domain 按钮继续:

3. 你需要根据网站给出的值,在你的域名注册商那里添加两个 TXT 记录,添加完成等该记录生效后,勾选 I Have My Own CSR 复选框,把前面使用 openssl 创建的 CSR 文件的内容粘贴到下面的文本框里,然后点击 Download SSL Certificate 按钮

如果 TXT 记录校验通过,ssoforfree 网站就会显示出颁发的证书内容了。你可以从文本框中复制 PEM 格式的证书内容,也可以直接点击下载包含证书文件的 ZIP 包。

注意,如果 CSR 文件是你自己提供的,那么下载的 ZIP 包中是不包含你的 Private Key 的,你需要保存好你之前使用 openssl 生成的 Private Key 文件。

五、在 nginx 中配置 SSL 证书

1. 生成 dhparam 文件:

# openssl dhparam -out dhparam.pem 2048

2. 把完整证书链保存在一个文件中

sslforfree 网站提供的证书的证书路径如下:

如果要想你的网站证书能受到信任并兼容所有设备(如 Android 设备上的浏览器),必须要把你的证书和根证书所有颁发机构的证书放在一个文件中,提供给客户端下载。从 sslforfree 下载的 ZIP 包中有 ca-bundle.crt 和 certificate.crt, 把这两个文件的内容粘贴到一个文件中。把 certificate.crt 文件中的内容放前面,ca-bundle.crt 中的内容放后面。根据我们的假设的例子,文件另存为 example.com.pem。示例内容如下:

-----BEGIN CERTIFICATE-----
[example.com证书内容]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[ca_bundle.crt证书链内容]
-----END CERTIFICATE-----

2. 在 nginx.conf 中添加 ssl 配置,包括 HTTP Header: Strict-Transport-Security, 指定 ssl_certificate, ssl_certificate_key,ssl_dhparam, 支持的协议:TLSv1 TLSv1.1 TLSv1.2 等,如下所示:

server {
listen 443 ssl;
server_name example.com www.example.com blog.example.com forum.example.com;

add_header Strict-Transport-Security max-age=31536000;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl on;
ssl_certificate /etc/ssl/example.com.pem;
ssl_certificate_key /etc/example.com.key;

ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/dhparam.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
keepalive_timeout 70;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

配置完成让 nginx reload 配置文件,访问网站就可以看到期待的锁图标及“安全”标识了。

六、安全检测

打开网站https://myssl.com/输入你的网址检测一下,看是不是达到的A+级安全标准:).

参考:

https://easyengine.io/wordpress-nginx/tutorials/ssl/multidomain-ssl-subject-alternative-names

CentOS 7 中安装配置Docker

· 6 min read

1. 通过下载 Binary 包安装 docker

在 CentOS 中,由于相关组件比较齐全,可直接下载 docker 的发布包直接启动,可以从下面的网页中找到下载链接:

https://docs.docker.com/install/linux/docker-ce/binaries/ https://download.docker.com/linux/static/stable/x86_64/

下载:

# curl -#O https://download.docker.com/linux/static/stable/`uname -m`/docker-17.12.1-ce.tgz

解压并 Copy 到/usr/bin/:

# tar xzvf docker-17.12.1-ce.tgz
# cp docker/* /usr/bin/

其他机器不用重复下载,sftp 到第一台机器直接 copy 过来:

#sftp [email protected]:/root/download/
sftp> get docker/*
sftp> exit

直接运行 dockerd

测试一下看能否成功启动 docker daemon:

接下来需要把 dockerd 配置成系统服务自动启动。

参照官方文档:https://docs.docker.com/config/daemon/systemd/#manually-create-the-systemd-unit-fileshttps://github.com/moby/moby/tree/master/contrib/init/systemd 把 docker.service 和 docker.socket 下载到/etc/systemd/system/目录

# curl -o /etc/systemd/system/docker.service https://raw.githubusercontent.com/moby/moby/master/contrib/init/systemd/docker.service
# curl -o /etc/systemd/system/docker.socket https://raw.githubusercontent.com/moby/moby/master/contrib/init/systemd/docker.socket

# systemctl daemon-reload
# systemctl enable docker

然后通过# systemctl start docker 启动 docker 服务,如果在启动过程中遇到如下错误:

- Unit docker.socket has begun starting up.
3月 22 00:47:07 centos02 systemd[1148]: Failed to chown socket at step GROUP: No such process
3月 22 00:47:07 centos02 systemd[1]: docker.socket control process exited, code=exited status=216
3月 22 00:47:07 centos02 systemd[1]: Failed to listen on Docker Socket for the API.
-- Subject: Unit docker.socket has failed

请检查/etc/systemd/system/docker.socket 文件中配置的 SockerGroup 对应的组是否存在,如果不存在则通过# groupadd 添加后再启动 docker 服务,从 github 上下载的 docker.socket 中配置的 SockerGroup 是 docker,需要先添加该 group:

# groupadd docker

然后再启动 docker 服务,启动成功:

docker 服务启动后,通过#docker version 查询 client 与 server 端版本信息:

其它自定义的 docker daemon 启动参数及环境变量可参考官方文档:https://docs.docker.com/config/daemon/systemd/, 通过 systemd drop-in 和 /etc/docker/daemon.json 配置。

2. 通过 yum repo 安装 docker

手动下载 binary 包的安装方式略显繁琐,通过 yum 安装的方式就会自动化和简单很多:

a) 添加 yum repo

# tee /etc/yum.repos.d/docker.repo <<-'EOF'
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF

b) 安装 docker

# yum install docker-engine

c) 启动 docker 服务并开机自动启动

# systemctl start docker
# systemctl enable docker

3. bridge-nf-call-iptables 问题

运行 docker info, 查看是否有提示 bridge-nf-call-iptables is disabled 和 bridge-nf-call-ip6tables is disabled 的 WARNNING:

# docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 1
Server Version: 17.12.1-ce
Storage Driver: overlay2
Backing Filesystem: xfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 9b55aab90508bd389d7654c4baf173a981477d55
runc version: 9f9c96235cc97674e935002fc3d78361b696a69e
init version: 949e6fa
Security Options:
seccomp
Profile: default
Kernel Version: 3.10.0-862.2.3.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 991.7MiB
Name: centos01
ID: KL2R:7F52:M5SV:T3U7:GL3Y:UU6F:KGE2:DM3Y:STSY:MLEZ:XXEL:EWG3
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false

WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled

通过添加以下配置解决:

# tee -a /etc/sysctl.conf <<-'EOF'
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
EOF
# sysctl -p

详细参见:关于 bridge-nf-call-iptables 的设计问题

3. 为 docker daemon 配置代理

有时候 docker 环境会运行在一个代理或防火墙内部,为了让 docker daemon 从外网 pull 镜像,就需要给 docker daemon 配置代理。有两种配置方式:

a) 通过 Service Drop-In 文件

例如我的代理地址为http://192.168.1.3:1080/:

# mkdir -p /etc/systemd/system/docker.service.d/
# tee /etc/systemd/system/docker.service.d/http-proxy.conf <<-'EOF'
[Service]
Environment="HTTP_PROXY=http://192.168.1.3:1080/" "HTTPS_PROXY=http://192.168.1.3:1080/" "NO_PROXY=192.168.1.1,192.168.1.3,192.168.1.11,192.168.1.12,192.168.1.13,192.168.1.14,192.168.1.99,127.0.0.1,localhost"
EOF
# systemctl daemon-reload
# systemctl restart docker

b) 修改/etc/systemd/system/docker.service 文件,在[Service]配置节添加 Environment:

[Service]
Environment="HTTP_PROXY=http://192.168.1.3:1080/" "HTTPS_PROXY=http://192.168.1.3:1080/" "NO_PROXY=192.168.1.1,192.168.1.3,192.168.1.11,192.168.1.12,192.168.1.13,192.168.1.14,192.168.1.99,127.0.0.1,localhost"

如果代理服务器需要认证,则配置格式为:http://username:[email protected]:1080/, 如果 username 或 password 中有特殊字符,则必须进行 encode。 如#要改成%23

c) 验证

# systemctl show --property Environment docker
Environment=HTTP_PROXY=http://192.168.1.3:1080/ HTTPS_PROXY=http://192.168.1.3:1080/ NO_PROXY=192.168.1.1,192.168.1.3,192.168.1.11,192.168.1.12,192.168.1.13,192.168.1.14,192.168.1.99,127.0.0.1,localhost

如果你的代理服务器是 HTTPS 的,有自己的 HTTPS 证书,那就更麻烦一些,你需要:

  1. 安装 ca-certificates 包
  2. 下载该 HTTPS 证书的 PEM 格式,保存到指定目录(CentOS 是放在/etc/pki/ca-trust/source/anchors/, Ubuntu 是放在/usr/local/share/ca-certificates/)
  3. 执行命令刷新信任证书(CentOS 中执行 update-ca-trust, Ubuntu 中执行 update-ca-certificates)

详见:

https://docs.docker.com/engine/reference/commandline/dockerd/#running-a-docker-daemon-behind-an-https_proxy

https://manuals.gfi.com/en/kerio/connect/content/server-configuration/ssl-certificates/adding-trusted-root-certificates-to-the-server-1605.html

4.其它配置参数

docker 服务还有很多其它参数可以通过 Drop-In, docker.service 或/etc/docker/daemon.json 进行配置,如添加一个本地镜像库,可以通过几种方式进行配置 :

a) 修改 docker.service 文件,在 dockerd 后面添加一个或多个--insecure-registry 192.168.1.3:10000

b) 修改/etc/docker/daemon.json,添加 insecure-registries 配置

{
"insecure-registries": ["192.168.1.3:10000"]
}

更新配置参数请参见:

https://docs.docker.com/engine/reference/commandline/dockerd/#daemon

https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file

附:安装 docker-compose

# curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/bin/docker-compose
# chmod +x /usr/bin/docker-compose
# docker-compose --version
docker-compose version 1.21.0, build 5920eb0

最新 Community 19.3.2 的安装方法

# yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

# yum install -y yum-utils \
device-mapper-persistent-data \
lvm2

# yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

# yum list docker-ce --showduplicates | sort -r

# yum install docker-ce docker-ce-cli containerd.io
ClustrMaps