在开始前:

  1. 请确保你阿里云服务器的安全组中开启了80端口和443端口。
  2. 确保你已经有了自己的域名并已经设置了正常的DNS解析地址。

安装Certbot工具

更新系统,安装安装Certbot及Nginx插件

这里非常简单,两行命令就搞定了。

1
2
3
4
5
# 更新系统包
sudo apt update && sudo apt upgrade -y

# 安装Certbot及Nginx插件
sudo apt install certbot python3-certbot-nginx

获取Let’s Encrypt证书

Certbot支持多种证书获取模式,包括Standalone模式、Webroot模式和DNS验证模式。使用Standalone模式获取证书是最简单的方式,无需现有Web服务器运行,但需要临时开放80端口。也就是说在运行下面命令前,你需要看一下自己的80端口现在有没有被占用,如果被占用了,需要及时将占用程序退出,否则会报错。

1
sudo netstat -tulnp | grep :80
  • 示例输出:tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1234/nginx → 进程名是 nginx

然后退出它就可以了:

1
2
sudo systemctl stop nginx  
# 若是 Apache:sudo systemctl stop apache2

然后运行 Certbot

1
2
# 示例:使用邮箱test@lovone.email为域名test.com申请SSL证书
sudo certbot certonly --standalone -d test.com --email test@lovone.email --agree-tos --noninteractive

正常情况下会在你的/etc/letsencrypt/live/test.com 文件夹下生成pem证书。

示例图片

配置自动续签任务

Certbot默认安装后会自动创建Cron定时任务,实现证书自动续签。
验证Cron任务是否已生成:

1
2
# 查看Certbot的Cron配置 
cat /etc/cron.d/certbot

输出应包含类似以下内容:

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && certbot -q renew

此配置表示每12小时(每天两次)检查证书有效期,如果剩余有效期少于30天,则自动续签.

如果希望确保证书续签后Docker容器内的Nginx服务能自动重新加载配置,需要在Cron命令中添加--post-hook参数:

1
2
3
4
# 编辑root用户的Cron任务 
sudo crontab -e
# 添加以下行
0 */12 * * * certbot renew --post-hook "docker exec lovone-nginx-blog nginx -s reload" > /dev/null 2>&1

此配置会在每12小时检查一次证书,如果需要续签,则执行续签操作,并在完成后通过docker exec命令重载容器内的Nginx服务,使新证书生效。

创建Dockerfile配置Nginx安全设置

1
2
3
4
5
6
7
8
9
10
11
# 使用国内镜像加速源获取基础镜像
FROM docker.1ms.run/nginx:alpine

# 隐藏Nginx版本信息
RUN sed -i 's/server_tokens on/server_tokens off/' /etc/nginx/nginx.conf

# 删除默认配置文件,避免冲突
RUN rm -rf /etc/nginx/conf.d/default.conf

# 添加自定义安全配置
COPY nginx.conf /etc/nginx/conf.d/

Dockerfile实现了三个关键的安全配置

  1. 使用国内镜像加速源docker.1ms.run/nginx:alpine提高镜像拉取速度
  2. 通过sed命令修改Nginx配置,隐藏版本信息(server_tokens off
  3. 删除默认配置文件default.conf,避免与自定义配置冲突

配置nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
server {
listen 80;
server_name your.domain.cn;# 这里替换成你的域名

# 禁止访问隐藏文件和隐藏文件夹
location ~^\.(git|env|log) {
deny all;
return 403;
}

# 所有HTTP请求重定向到HTTPS
location / {
return 301 https://$host$request_uri;
}
}

server {
listen 443 ssl;
server_name your.domain.cn;# 这里替换成你的域名

# 隐藏Nginx版本信息
server_tokens off;

# 禁用目录列表
autoindex off;

# 禁止访问隐藏文件和隐藏文件夹
location ~^\.(git|env|log) {
deny all;
return 403;
}

# SSL证书配置
ssl_certificate /etc/letsencrypt/live/your.domain.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your.domain.cn/privkey.pem;

# SSL安全参数
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;

# 静态文件配置
root /usr/share/nginx/html;
index index.html index.htm;

# 日志配置
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}

配置文件实现了基本的安全要求

  • 隐藏Nginx版本信息(server_tokens off
  • 禁止访问以点开头的隐藏文件和文件夹(location ~^\.(git|env|log)规则)
  • 禁用目录列表(autoindex off
  • 在HTTP端口(80)上将所有请求重定向到HTTPS
  • 配置SSL证书路径和安全参数

编写docker-compose.yml

接下来创建docker-compose.yml文件,定义Nginx服务并配置卷挂载,确保证书和博客源码可以访问:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '3.8'

services:
nginx:
image: lovone-blog:latest
container_name: lovone-nginx-blog
ports:
- "80:80"
- "443:443"
volumes:
- /root/web/网站静态文件的目录:/usr/share/nginx/html
- /etc/letsencrypt:/etc/letsencrypt
restart: unless-stopped
command: nginx -g "daemon off;"

docker-compose.yml文件实现了关键的卷挂载功能

  • 将物理机上的博客源码目录挂载到容器的/usr/share/nginx/html目录
  • 将物理机上的Let’s Encrypt证书目录挂载到容器的/etc/letsencrypt目录

通过这种挂载方式,容器内的Nginx可以访问最新的博客内容和证书,无需重新构建镜像即可更新。Certbot在物理机上获取和续签的证书会自动同步到容器中。

构建自定义Nginx镜像并启动服务

1
2
3
4
5
6
7
8
# 构建镜像 
docker build -t lovone-nginx:latest .

# 创建证书存储目录(如果尚未创建)
mkdir -p /etc/letsencrypt

# 启动Nginx服务
docker compose up -d

此时你在浏览器中访问test.com,浏览器会先访问http://test.com ,随后跳转到https://test.com,表示此时已成功配置好SSL证书。

https时刻!

维护与升级

随着博客内容的更新和Nginx配置的调整,需要定期维护和升级服务:

1
2
3
4
5
6
7
8
# 拉取最新的博客源码
git pull

# 重新加载Nginx配置使更新生效
docker exec lovone-nginx-blog nginx -s reload

# 定期检查证书状态,注意:该命令不会实际更新证书,可以用来检查证书续签是否正常工作
certbot renew --dry-run

Good Luck !