前言
最近在搞苹果应用上架的问题,据说用HTTP会被拒,但貌似不绝对,2017年苹果曾发公告说必须要求HTTPS,紧接着便说延缓这个决定,也就是说现在用HTTP也不一定会被限制,但是确实存在风险,所以想着最近把HTTP请求升级成HTTPS,本着折腾的精神(其实还是穷)搞一搞免费证书,Let’s Encrypt 这个组织之前一篇文章《使用 Let’s Encrypt 获取免费SSL证书》 曾讲到过,我们今天来说下这个证书怎么用,算是给我自己出个教程,拯救一下我记忆力减退的大脑~
证书申请
使用Let’s Encrypt申请SSL证书,可以选择 DNS-01
验证或者 HTTP-01
验证,其中 HTTP-01
可以利用类似 nginx
插件完成证书的自动更新,因为我的环境有点尴尬,80端口总是被各种服务占用,一直也没有成功,但还是列举下步骤,等待后面尝试
sudo yum install epel-release
sudo yum install certbot python2-certbot-nginx # 安装依赖,Ubuntu安装python-certbot-nginx
sudo certbot --nginx -d www.example.com # 生成验证SSL证书
sudo systemctl list-timers # 验证自动续期是否已经配置
sudo certbot renew --dry-run # 确保自动续期正常工作
sudo systemctl reload nginx # 诚信加载配置
openssl s_client -connect www.example.com:443 # 测试证书是否可用
使用 DNS-01
验证可以生成证书后手动配置,命令很简单 sudo certbot certonly --manual --preferred-challenges dns -d www.example.com
,具体步骤我就不重复写了,参考上篇
证书介绍
假设我为 checkssl.008ct.space
成功生成了证书,那么会得到以下4个文件,分别介绍一下它们
[root@VM-0-3-centos live]# ll /etc/letsencrypt/live/checkssl.008ct.space/
total 4
lrwxrwxrwx 1 root root 38 Feb 28 13:45 cert.pem -> ../../archive/checkssl.008ct.space/cert1.pem
lrwxrwxrwx 1 root root 39 Feb 28 13:45 chain.pem -> ../../archive/checkssl.008ct.space/chain1.pem
lrwxrwxrwx 1 root root 43 Feb 28 13:45 fullchain.pem -> ../../archive/checkssl.008ct.space/fullchain1.pem
lrwxrwxrwx 1 root root 41 Feb 28 13:45 privkey.pem -> ../../archive/checkssl.008ct.space/privkey1.pem
-rw-r--r-- 1 root root 692 Feb 28 13:45 README
cert.pem
- 这是 服务器证书(Server Certificate),它是 Let’s Encrypt 为你的域名生成的证书,代表你的服务器身份。
- 它包含了你的公钥和其他证书信息。
- 你需要将它配置到 Nginx 中,以便客户端能够验证服务器的身份。
chain.pem
- 这是 中间证书(Intermediate Certificate),它链接了你的证书和根证书(Root Certificate)。
- 客户端在验证服务器证书时,需要通过链条的中间证书才能找到受信任的根证书。因此,
chain.pem
文件有助于建立证书链的完整性。
fullchain.pem
- 这是将 服务器证书 和 中间证书 合并在一起的文件。它包含了
cert.pem
和chain.pem
的内容,客户端验证时需要的是完整的证书链。 - 推荐在 Nginx 配置中使用
fullchain.pem
,因为它包含了所有必要的证书链信息。
privkey.pem
- 这是 私钥(Private Key),它是你服务器的私密密钥。它用来加密和解密 SSL/TLS 会话。
- 该文件必须与证书配对,并且应该非常小心地保管,避免泄露。泄露私钥会导致证书被滥用。
使用步骤
证书已经生成好了,假设我们之前有一个引用,支持http和websocket协议,HTTP监听8881端口,WS监听8882端口,通过域名 checkssl.008ct.space
访问,现在需要把他们改成支持HTTPS和WSS,直接修改应用的代价比较大,同时加解密放到应用程序上带来性能损失,这里就可以利用nginx来完成SSL终止,具体操作如下:
搭建简易demo应用
直接用 python3 写一个web应用就行,将以下内容保存到文件app.py中, 通过 python3 app.py
运行即可
import asyncio
import threading
import websockets
from flask import Flask
# 创建 Flask 应用(HTTP 服务)
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello from HTTP server on port 8881!"
# WebSocket 处理函数
async def websocket_handler(websocket, path):
print(f"New WebSocket connection: {websocket.remote_address}")
await websocket.send("Hello from WebSocket server on port 8882!")
await websocket.wait_closed()
# 启动 Flask 应用的线程(HTTP 服务)
def start_flask():
app.run(host='0.0.0.0', port=8881)
# 启动 WebSocket 服务的线程
def start_websocket():
# 为子线程创建一个新的事件循环
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
start_server = websockets.serve(websocket_handler, "0.0.0.0", 8882)
loop.run_until_complete(start_server)
loop.run_forever()
# 启动两个服务(HTTP 和 WebSocket)
if __name__ == '__main__':
# 启动 HTTP 服务
flask_thread = threading.Thread(target=start_flask)
flask_thread.start()
# 启动 WebSocket 服务
websocket_thread = threading.Thread(target=start_websocket)
websocket_thread.start()
新建nginx配置文件
在目录 /etc/nginx/conf.d/
下创建 checkssl.conf
文件,编写内容如下:
server {
listen 8871 ssl;
server_name checkssl.008ct.space;
# SSL 配置
ssl_certificate /etc/letsencrypt/live/checkssl.008ct.space/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/checkssl.008ct.space/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
# HTTP 转发到 8881 端口
location / {
proxy_pass http://127.0.0.1:8881; # 转发到 HTTP 服务(Flask)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 8872 ssl;
server_name checkssl.008ct.space;
# SSL 配置
ssl_certificate /etc/letsencrypt/live/checkssl.008ct.space/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/checkssl.008ct.space/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
# WebSocket 转发到 8882 端口
location / {
proxy_pass http://127.0.0.1:8882; # 转发到 WebSocket 服务
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 配置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
}
}
编写完成重新加载配置文件,使用命令 nginx -s reload
测试SSL是否生效
测试 HTTPS
直接在浏览器访问 https://checkssl.008ct.space:8871
就行了,在地址栏会显示一把小锁表示网站安全,但是测试 WSS
就不能直接用浏览器了,可以使用python脚本或者js脚本来测试,这里我们用html页面内嵌js来发送WSS请求,点击按钮后发现也是能正常访问服务的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Test</title>
</head>
<body>
<h1>WebSocket Test</h1>
<button onclick="connect()">Connect to WebSocket</button>
<div id="message"></div>
<script>
let socket;
function connect() {
socket = new WebSocket('wss://checkssl.008ct.space:8872');
socket.onopen = function() {
document.getElementById('message').innerHTML = 'Connected to WebSocket!';
socket.send("Hello Server!");
};
socket.onmessage = function(event) {
document.getElementById('message').innerHTML = 'Message from server: ' + event.data;
};
socket.onerror = function(error) {
document.getElementById('message').innerHTML = 'Error: ' + error.message;
};
socket.onclose = function() {
document.getElementById('message').innerHTML = 'WebSocket connection closed.';
};
}
</script>
</body>
</html>
发现一个秘密,一直我还以为自己使用这只有90天有效期的 Let's Encrypt
的有点麻烦,今天才发现Vercel平台免费颁发的证书都是这种,不过也够用了,AWS的证书倒是会标记组织为 Amazon
总结
- 选择
HTTP-01
验证需要占用80端口,可以通过插件实现SSL证书的自动续期 - 使用
DNS-01
验证得手动添加DNS记录,命令就一条sudo certbot certonly --manual --preferred-challenges dns -d www.example.com
- Nginx可以完成SSL终止,将HTTPS转为HTTP,将WSS转为WS,降低应用服务器的负载
- Let’s Encrypt 颁发的证书有效期是 90 天,减少了证书被泄露或滥用的潜在的风险,鼓励用户采用自动化续期机制
父王只是想用自己的经验为你谋个幸福,但现在看来,父辈的经验,毕竟是过往,未必全对,你的路还需你去闯。今后,忠于自己内心的选择吧~
2025-2-22 08:30:00 在这个和父亲第一次一起看电影的影院里,屏幕上出现了这段话,一切都像是被安排好了一样。