/ https

https

不使用 HTTPS 存在的风险

  • 窃听风险(eavesdropping):第三方可以获知通信内容。
  • 篡改风险(tampering):第三方可以修改通信内容。
  • 冒充风险(pretending):第三方可以冒充他人身份参与通信。

To enable HTTPS on your website, you need to get a certificate (a type of file) from a Certificate Authority (CA). Let’s Encrypt is a CA.

注意 网站一旦启用 https,则附加的 css、js、image 都要是 https 的。如果 网站使用第三方 CDN 则会产生额外的费用。

阿里云

产品与服务,CA 证书:

  1. 选择品牌Symantec
  2. 保护类型1个域名
  3. 证书类型免费型DV SSL

证书生成之后,需推送到 CDN 或负载均衡!

Let's Encrypt

Let's Encrypt 的 certificates(有效期90天),配合 certbot 自动续期。

下载安装 certbot

# CentOS 7
sudo yum install epel-release

参考官方文档安装 certbot : https://certbot.eff.org/

The certbot Let's Encrypt client is now installed and ready to use.

certbot --version

Get start

然后执行:

sudo certbot --authenticator webroot --installer nginx

认证过程

  1. 邮箱使用国内邮箱(不建议使用 gmail),在证书快过期时,会发送通知邮件
  2. 如果遇到 "installing Python packages" 停住不动时,请使用阿里云的pip 镜像。

生成证书成功

  • Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/example.com/fullchain.pem
    ...

注意这里,默认会自动生成 /var/www/example/.well-known/acme-challenge,然后 shell 脚本会对应的访问该文件,如果返回正常就确认了你对这个网站的所有权,就能顺利生成证书。

生成的证书会存储在 /etc/letsencrypt/live/example.com/ 对应的目录下。

  • cert.pem - Your domain's certificate
  • chain.pem - The Let's Encrypt chain certificate
  • fullchain.pem - cert.pem and chain.pem combined
  • privkey.pem - Your certificate's private key

初始配置为 http://mydomain.com 正常可访问:

server {
	listen 80;
	listen [::]:80;
	server_name mydomain.com;

	include /etc/nginx/snippets/letsencrypt.conf;

	location / {
		proxy_pass http://127.0.0.1:3999;
	}
}

Renew

ImportError: No module named 'requests.packages.urllib3'

for CentOS7,Just do

mv /usr/lib64/python2.7/site-packages/OpenSSL /usr/lib64/python2.7/site-packages/pyOpenSSL

and that works like a charm for me!!!

nginx 重新加载配置

要让修改后的配置生效,不需要 restart ,只需要 reload 即可:

sudo service nginx reload

测试 SSL 安全性

立即前往测试,输入域名,查看评测报告,应该有 A+

自动续期 cron

建议一天跑两次自动续期任务。

先测试下自动续期是否正常:

sudo certbot renew --dry-run

查看下 certbot 全路径:

➜  ~ which certbot
/usr/bin/certbot

如果一切正常,则添加自动续期任务:

sudo crontab -e

Add the following lines:

which certbot

每天 5 点和 22 点检查一次,为了避免对整点整分对证书服务器请求的压力,随机在预定一小时内获取证书:

# 分 时 日 月 周
* 5,22 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew 

如果证书更新了,certbot 会自动重启 nginx 来加载新证书。

确认下任务

sudo crontab -l

即每周 1 的 02:30 更新证书,02:35 重启 nginx (so the renewed certificate will be used)。
更新证书的日志会放在 /var/log/le-renewal.log
如果到期没有更新证书,CA会向申请证书时提交的邮件地址发送提醒email。

HTTPS站点的SEO自检清单

  1. 确保网站的每个元素(包括插件、JS、CSS文件、图片、内容分发网站等)都采用HTTPS协议;
  2. 使用301重定向将HTTP URL指向HTTPS版地址

404 on .well-known/acme-challenge/

检查 /etc/letsencrypt/renewal 目录下的配置文件中的路径。申请证书后变更了 root 路径,会造成更新证书时的 404 错误。

补充

测试更新时报错,可以追加 --debug

sudo certbot renew --dry-run --debug

管理证书:

sudo certbot certificates

删除证书:

sudo certbot delete
sudo certbot delete --cert-name example.com

Nginx 配置生成器 - Mozilla SSL Configuration Generator

nginx 配置

创建文件 /etc/nginx/snippets/letsencrypt.conf

location ^~ /.well-known/acme-challenge/ {
	default_type "text/plain";
	root /var/www/letsencrypt;
}

Create the folder for the challenges:

sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge

Create a file /etc/nginx/sites-available/mydomain.conf containing:

server {
  listen 80 default_server;
  listen [::]:80 default_server ipv6only=on;
  server_name mydomain.com www.mydomain.com;
  
  # 引入 Let's Encrypt  验证域名需要的配置
  include /etc/nginx/snippets/letsencrypt.conf;

  root /var/www/mydomain;
  index index.html;
  location / {
    try_files $uri $uri/ =404;
  }
}

运行 certbot :

sudo certbot --authenticator webroot --installer nginx

提示输入 webroot 时,填入 /var/www/letsencrypt 即可。

或者仅仅获取证书(certonly),不需要重定向或者其他修改,并且指定域名(-d):

sudo certbot certonly --webroot -w /var/www/letsencrypt -d www.example.com -d example.com 

It will save the files in /etc/letsencrypt/live/www.mydomain.com/.

扩展一个证书:

sudo certbot --expand -d existing.com,example.com,new.example.com

Nginx virtual hosts (HTTPS-only)

## http://mydomain.com redirects to https://mydomain.com
server {
	listen 80;
	listen [::]:80;
	server_name mydomain.com;

	include /etc/nginx/snippets/letsencrypt.conf;

	location / {
		return 301 https://mydomain.com$request_uri;
	}
}

## http://www.mydomain.com redirects to https://www.mydomain.com
server {
	listen 80 default_server;
	listen [::]:80 default_server ipv6only=on;
	server_name www.mydomain.com;

	include /etc/nginx/snippets/letsencrypt.conf;

	location / {
		return 301 https://www.mydomain.com$request_uri;
	}
}

## https://mydomain.com redirects to https://www.mydomain.com
server {
	listen 443 ssl http2;
	listen [::]:443 ssl http2;
	server_name mydomain.com;

	ssl_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/www.mydomain.com/privkey.pem;
	ssl_trusted_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
	include /etc/nginx/snippets/ssl.conf;

	location / {
		return 301 https://www.mydomain.com$request_uri;
	}
}

## Serves https://www.mydomain.com
server {
	server_name www.mydomain.com;
	listen 443 ssl http2 default_server;
	listen [::]:443 ssl http2 default_server ipv6only=on;

	ssl_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/www.mydomain.com/privkey.pem;
	ssl_trusted_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
	include /etc/nginx/snippets/ssl.conf;

	root /var/www/mydomain;
	index index.html;
	location / {
		try_files $uri $uri/ =404;
	}
}

开发环境禁止 chrome 跳转 https

Step1. 规避强制 https 的域名

Chrome 63 开始 *.dev 域名强制使用 https,所以开发域名不要使用 dev。app 也是强制,所以要规避以下开发域名:

  • dev
  • app

homestead.app 改为 homestead.io

Step2. 从 https 清单中删除对应域名

chrome://net-internals/#hsts

Query HSTS/PKP domain中查询指定的域是否有HSTS记录,如果存在,在Delete domain security policies中删除该域即可。

Delete domain security policies 输入 homestead.io 然后按下 delete

如果查找不到指定的域名,就需要清空浏览器缓存。

Step3. 清空缓存

同一个 Url 一旦加载过 https,就会一直跳转到 https。这时候就需要清空缓存来解决。

Chrome 安装扩展 Clear Cache,点击一下就可以清空缓存。再次访问 http 地址就不会跳转到 https 了。

error

An unexpected error occurred:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 15: ordinal not in range(128)

nginx 配置文件中不能出现中文,删除注释中的汉字就好了。

参考列表: