通过 Docker 部署 Nginx 配置反向代理,并通过 Certbot 获取免费 SSL 证书

Limonene Lv1

上次部署博客还是在腾讯云的「轻量应用服务器」,并使用了附带「宝塔」面板的镜像。因此,诸如部署 Wordpress、配置 Nginx 反向代理、申请 SSL 证书等操作都是通过腾讯云的 GUI 或者宝塔的 WebUI 完成的。这次换用了 Hexo 框架,并且出于某种「依赖洁癖」,选择使用容器化的 Docker Nginx,而不是直接部署 Nginx,于是一下子就不知道该怎么从头配置了。这里记录一下折腾的过程,也希望能帮到其他人。

Ngixn 反向代理(Reverse Proxy)以及 SSL 证书的作用就不多赘述了,这里主要讲一下该怎么通过 Certbot 从 Let’s Encrypt 获取 SSL 证书,以及怎么配置 Nginx 的 Config 文件实现反向代理。

另外,本站目前已经迁移到 Cloudflare Pages(白折腾了),后续或许会再写一篇关于在 Cloudflare Pages 搭建 Hexo 博客的文章。

通过 Docker 部署 Nginx,并通过 Certbot 获取 SSL 证书

本部分主要参考了 Minders Blog 的这篇文章 。这里假定你对 Docker Compose 有一定的了解。

首先创建一个用于存放 Nginx 相关配置、证书等文件的文件夹,并在文件夹下创建如下的 docker-compose.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
version: '3'

services:
webserver:
image: nginx:latest
ports:
- 80:80
- 443:443
restart: unless-stopped
volumes:
- ./nginx/conf/:/etc/nginx/conf.d/:ro
- ./certbot/www:/var/www/certbot/:ro
- ./certbot/conf/:/etc/nginx/ssl/:ro
certbot:
image: certbot/certbot:latest
volumes:
- ./certbot/www/:/var/www/certbot/:rw
- ./certbot/conf/:/etc/letsencrypt/:rw

这里大概解释一下这个文件描述的配置:

  • 将宿主机的 80、443 端口绑定到 Nginx 容器的 80、443 端口,用于处理 HTTP 与 HTTPS 请求。
  • 将当前目录下的 ./nginx/conf 文件夹挂载到 Nginx 容器内的配置文件夹,用于存储 Nginx 配置文件。所有这些挂载的文件夹如果不存在,docker compose 都会自动创建。
  • 将当前目录下的 ./certbot/www 同时挂载到 Nginx 容器及 Certbot 容器。这个目录是用于 SSL 验证的。CA 颁发证书给你的前提,是你能证明这个域名确实属于你。因此,一般会通过下发给你特定文件,并要求你将文件放入服务器特定位置,再由 CA 读取文件来完成身份验证。这里使用的 Certbot 容器就是为了简化这一验证步骤,自动化地完成上述验证流程。因此,需要一个共享文件夹,来完成验证文件到 Nginx 服务器的传递。
  • 将当前目录下的 ./certbot/conf/ 同时挂载到 Nginx 容器及 Certbot 容器。这个目录将会用于存储 Certbot 申请的证书。

如果你按照我接下来的步骤遇到了什么问题,也可以访问开头提到的 Minders Blog 一步一步构建 docker-compose.yml,但是按照我的理解,直接采用最终版就可以了。

Step 1:初次启动

在根目录(也就是docker-compose.yml 所在的位置)通过 docker compose up -d 启动容器。第一次启动时,会首先从网络下拉 Nginx 与 Certbot 容器的镜像,耐心等待启动完成即可。启动完成后,上述三个文件夹应该被自动创建好了。

Step 2:修改 Nginx 配置文件

./nginx/conf 这个路径下创建一个配置文件,例如 nginx.conf,并填入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
listen 80;
listen [::]:80;

server_name example.org;
server_tokens off;

location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

location / {
return 301 https://example.org$request_uri;
}
}

别忘记把所有的 example.org 替换为你自己的域名。

  • 这个文件定义了一个 server,监听在 IPv4 和 IPv6 的 80 端口,对应的域名是 example.org
  • 后面两条 location 比较重要。
    • 第一条定义了当访问 http://example.org/.well-known/acme-challenge/ 时,应该展示 /var/www/certbot 中的内容,这是用于 CA 验证。
    • 第二条定义了其余所有位置的访问,都应该被 301 重定向到 https://example.org,并保留末尾的 $request_uri

这样,用户通过 HTTP 协议访问你的域名时,就会被重定向到 HTTPS 站点。当然,目前我们还没有配置 Nginx 的 HTTPS 服务器,所以重定向后只能访问到默认界面。

如果你要申请的证书不是指向你的 Apex Domain(不带任何次级域名),那你可以先暂停在这里继续读下去,后面会讲次级域名 SSL 证书的申请。

Step 3:申请 SSL 证书

通过 docker compose restart 重启两个容器。此时,Nginx 的配置应该已经生效了。接着运行

1
docker compose run --rm  certbot certonly --webroot --webroot-path /var/www/certbot/ --dry-run -d example.org

模拟颁发证书的流程。别忘了将 example.org 换成你自己的域名,并且确保DNS解析正常,通过域名能正常访问到你的 Nginx 服务器。Certbot 可能会询问你的信息,用于在 Let’s Encrypt 注册,正常填写即可。如果最后看到 successful,说明模拟过程没有问题,就可以去掉 --dry-run 参数,真正完成证书颁发流程了。

1
docker compose run --rm  certbot certonly --webroot --webroot-path /var/www/certbot/ -d example.org

配置 Nginx 反向代理

在上一步中申请到域名证书后,我们就可以继续修改 Nginx 的配置文件,配置反向代理了:

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
server {
listen 80;
listen [::]:80;

server_name example.org www.example.org;
server_tokens off;

location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

location / {
return 301 https://example.org$request_uri;
}
}

server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;

server_name example.org;

ssl_certificate /etc/nginx/ssl/live/example.org/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/example.org/privkey.pem;

location / {
proxy_pass http://<local IP>:<local port>/;
}
}

讲一下新增的部分。

  • 新增的 server,监听在 IPv4 和 IPv6 的 443 端口,并且开启了 SSL 与 HTTP2,对应的域名是 example.org

  • 后面两条 ssl_certificate 指向你上一步申请到的 SSL 证书。注意,路径中的 example.org 也要替换为你的真实域名。如果不确定的话,可以 docker exec -it <container> bash 进入 Nginx 容器确认一下路径。

  • 后面一条 location 实现了反响代理的部分。将 <local IP><local port> 替换为你本地运行的 HTTP 服务,当用户通过 https://example.org 访问你的网站时,实际访问到的是反向代理的页面,并且通过 SSL 加密。

    注意:因为 docker 创建了虚拟子网,因此宿主机上的服务并不能直接通过 127.0.0.1 访问。

    • 可以通过 ip a 指令检查宿主机的所有网络界面,并找到宿主机在 docker 子网中的 IP,例如 172.17.0.1/16
    • 如果不需要隔离容器与宿主机网络,可以去掉 docker-compose.ymlports 的部分,并将网络模式设置为 host,这里不多赘述,别忘记通过 docker compose up -d 重新创建容器。然后就可以通过 127.0.0.1 直接访问宿主机服务。
    • 如果要暴露 80(HTTP)、443(HTTPS)以外的端口,同样要修改 docker-compose.ymlports 的部分,并通过docker compose up -d 重新创建容器。

通过 docker compose restart 重启 Nginx 容器后,即可实现通过 SSL 反向代理本地服务。

提示

如果使用 Cloudflare CDN 为博客加速,需要在 SSL/TLS 选项中将加密模式选中为 Full (strict),在 Flexible 模式下,Cloudflare 会试图访问你的 HTTP 站点,导致循环重定向,最终用户浏览器会报「重定向过多」错误。

为子域名申请证书及配置反向代理

通常我们会将站点的子域名指向不同的服务,并通过 Nginx 统一反向代理,例如 overleaf.example.org 指向本地部署的 Overleaf、qb.example.org 指向 qBitTorrent 的 WebUI 等。想为子域名申请 SSL 证书,和上面的流程基本一致。首先修改 nginx.conf,继续加入对应子域名的服务器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ......
server {
listen 80;
listen [::]:80;

server_name <subdomain>.example.org;

location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

location / {
proxy_pass http://<local IP>:<local port>/;
}
}

如果你在这里配置的子域名是 www,并且希望子域名和 Apex Domain 都指向你的主服务(例如博客),可以在 301 重定向的部分直接指向你的 https://example.org

重复上述的申请证书流程,就能申请到对应子域名 <subdomain>.example.org 的证书了。然后继续添加 HTTPS 服务器:

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
# ......
server {
listen 80;
listen [::]:80;

server_name <subdomain>.example.org;

location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

location / {
return 301 https://<subdomain>.example.org$request_uri;
}
}

server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;

server_name <subdomain>.example.org;

ssl_certificate /etc/nginx/ssl/live/<subdomain>.example.org/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/<subdomain>.example.org/privkey.pem;

location / {
# return 301 https://example.org$request_uri;
return 301 https://<subdomain>.example.org$request_uri;
}

}

如果是 www 子域名,可以 301 重定向到你的主域名。如果是其他服务,可以反向代理到本地的其他服务。别忘记 docker compose restart 应用配置修改。

证书续签

Let’s Encrypt 颁发的证书有效期比较短,别忘记及时续签。通过 docker compose run --rm certbot renew 命令,即可通过 Certbot 自动续签全部证书。同样可以加上 --dry-run 参数模拟续签流程。

  • 标题: 通过 Docker 部署 Nginx 配置反向代理,并通过 Certbot 获取免费 SSL 证书
  • 作者: Limonene
  • 创建于 : 2024-01-09 00:37:21
  • 更新于 : 2024-01-23 19:57:29
  • 链接: https://limonene.top/2024-01-08/通过-Docker-部署-Nginx-配置反向代理,并通过-Certbot-获取免费-SSL-证书/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论