ssl 证书安装到 docker 服务器
1. 下载证书
从服务商处下载证书,下载 Nginx(适用大部分场景)(pem 文件、crt 文件、key 文件)。
2. 使用证书,以及构建镜像
项目文件目录为:
以下所有的 strive.online
为域名,使用时请替换成自己的域名。
├── Dockerfile
├── nginx.conf
├── certs
│ ├── strive.online_bundle.pem
│ └── strives.online_bundle.crt
│ └── strive.online.key
│ └── strives.online.csr
Dockerfile 文件内容为:
FROM nginx:mainline-alpine
COPY ./nginx.conf /etc/nginx/nginx.conf
COPY ./certs/strives.online_bundle.pem /path/to/strives.online_bundle.pem
COPY ./certs/strives.online.key /path/to/strives.online.key
# 暴露需要的端口 根据nginx.conf文件 配置几个server,就暴露几个端口
EXPOSE 443
注意点:
COPY 到镜像里的证书路径需要和 nginx.conf 文件中配置的路径一致。
EXPOSE 443 根据 nginx.conf 文件配置的端口来暴露,如果有多个 server,就暴露多个端口。
nginx.conf 文件内容为:
events {
worker_connections 1024; # 每个工作进程允许的最大连接数
}
http {
include /etc/nginx/mime.types; # 包含 MIME 类型配置文件
default_type application/octet-stream; # 默认的 MIME 类型
# ----- 反向代理 -----
# Nginx 只会把 HTTPS 的默认端口 443 代理到 HTTP 的默认端口 80,
# 因为你在 proxy_pass 指定的是 http://strives.online,默认会使用 HTTP 的 80 端口。
server {
listen 443 ssl; # 监听 443 端口,表示 HTTPS
server_name strives.online; # 指定域名
# 指定 SSL 证书和私钥的位置
ssl_certificate /path/to/strives.online_bundle.pem;
ssl_certificate_key /path/to/strives.online.key;
# 添加一些推荐的 SSL 配置
ssl_protocols TLSv1.2 TLSv1.3; # 只启用安全协议版本
ssl_ciphers HIGH:!aNULL:!MD5; # 安全密码套件
ssl_prefer_server_ciphers on; # 优先使用服务器端的密码配置
ssl_session_cache shared:SSL:10m; # SSL 会话缓存 大小 10MB
ssl_session_timeout 10m; # SSL 会话超时时间 10 分钟
location / {
proxy_pass http://strives.online; # 将请求代理到 HTTP 的默认端口80,那么docker内部服务就应该监听 80 端口,就是docker容器里ports 80/tcp的由来
proxy_set_header Host $host; # 传递客户端请求的 Host 头
proxy_set_header X-Real-IP $remote_addr; # 传递客户端请求的真实 IP 地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递客户端请求的原始 IP 地址 和代理服务器 IP 地址
proxy_set_header X-Forwarded-Proto $scheme; # 传递客户端请求的协议(http 或 https)
# 可根据需要设置超时时间或缓冲区大小
# proxy_read_timeout 90;
# proxy_buffer_size 16k;
# proxy_buffers 4 32k;
# proxy_busy_buffers_size 64k;
}
}
# ----- 反向代理 -----
# 这里也是因为我们容器要开启8088端口,所以我们的api容器就不能再开启8088端口了,所以这里监听8089端口,然后重定向到8088端口使得外部访问https8088端口
server {
listen 8088 ssl; # 监听宿主机的 8088 端口,使用 SSL
server_name strives.online; # 替换为你的域名
ssl_certificate /path/to/strives.online_bundle.pem;
ssl_certificate_key /path/to/strives.online.key;
ssl_protocols TLSv1.2 TLSv1.3; # 使用现代的 TLS 协议
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
# proxy_pass http://localhost:8089; # 每个容器都是独立的,所以这里不能使用localhost 对 Nginx 容器来说只指向它自己,而不是指向你的应用服务,所以这里应该使用strives.online。
proxy_pass http://strives.online:8089; # 将请求转发到 Docker 容器的 8089 端口
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;
}
}
# ----- 重定向 -----
# # 处理 HTTP 8089 端口请求,重定向到 HTTPS 8088
# server { # 这里因为docker 容器运行在8088端口,api镜像就不能再启动8088端口所以这里监听api的8089端口,然后重定向到8088端口
# listen 8089; # 监听 HTTP 8089 端口
# server_name strives.online;
# ssl_certificate /path/to/strives.online_bundle.pem;
# ssl_certificate_key /path/to/strives.online.key;
# location / {
# return 301 https://$host:8088$request_uri; # 将 HTTP 8089 的请求重定向到 HTTPS 8088
# }
# }
}
注意点:
在 nginx.conf 文件中,我们使用
proxy_pass http://strives.online;
将请求代理到 HTTP 的默认端口 80,所以容器内部的服务应该监听 80 端口。如果容器内部的服务监听的是 8088 端口,那么在 nginx 配置文件中,应该使用
proxy_pass http://strives.online:8088;
将请求代理到 8088 端口。使用的是反向代理,代理的地址就是域名
strives.online
,而不是localhost
或者127.0.0.1
,因为容器是独立的,所以不能使用localhost
或者127.0.0.1
。再次强调,我们这里配置了 N 个 server,就需要在 dockerfile 中暴露 N 个端口。
3. 打包为镜像 运行在自己的 docker 服务器上
打包本地镜像:
docker build --load -t https-ssl .
打包远程仓库镜像:
docker buildx build --platform linux/amd64 --load -t dockerName/https-ssl:1.0.0 .
这里需要登录 docker,没有 dockerName/https-ssl 会进行创建,有的话会进行更新。 构建为 linux/amd64 架构的镜像,原因请参考 打包多平台镜像。
推送镜像到 docker 仓库:
docker push dockerName/https-ssl:1.0.0
在 docker 服务器上拉取镜像:
docker pull dockerName/https-ssl:1.0.0
docker 服务器运行容器:
docker run -d -p 443:443 --name https-ssl images:versions
运行容器有个注意点:
- 因为我们在 nginx 配置文件中监听了 443 端口,所以我们需要将容器的 443 端口映射到主机的 443 端口,如果我们上面配置了多个端口,那么我们需要将容器的多个端口映射到主机的多个端口。
例如:
docker run -d -p 8088:8088 -p 443:443 --name https-ssl images:versions
4. 测试
在浏览器中输入 https://strives.online
,如果能够正常访问,说明 ssl 证书已经安装成功。
5. 配置后执行流程
用户请求:用户访问 https://strives.online,浏览器发送 HTTPS 请求。
Docker 网络:请求首先到达 Docker 容器的 443 端口。
SSL/TLS 握手:Nginx 接收到请求后,首先进行 SSL/TLS 握手,以确保连接的安全性。
Nginx 反向代理:Nginx 充当反向代理,负责处理所有外部的 HTTPS 请求。
配置解析:请求进入 Nginx 配置文件中的 server 块。Nginx 根据请求的 Host 头和 URI 来决定如何处理请求。
请求匹配和转发:如果请求的 URI 是 /,Nginx 会匹配到相应的 location 块,并使用 proxy_pass http://strives.online; 将请求转发到内部的 HTTP 服务容器。
负载均衡(可选):如果配置了多个后端服务,Nginx 可以根据策略进行负载均衡。
内部服务处理:在容器内部,HTTP 服务处理请求,并生成响应。
响应返回:HTTP 服务将响应返回给 Nginx,Nginx 再将响应传递给客户端。
缓存(可选):如果配置了缓存,Nginx 可以缓存响应,以提高后续请求的速度。
6. 问题延申
http 的默认端口是 80,https 的默认端口是 443,但是为什么在 docker 中查看启动的容器端口监听的是 80 (80/tcp)端口,而不是 443 端口?
因为在 nginx 配置文件中,我们使用
proxy_pass http://strives.online;
将请求代理到 HTTP 的默认端口 80,所以容器内部的服务应该监听 80 端口。如果容器内部的服务监听的是 8088 端口,那么在 nginx 配置文件中,应该使用
proxy_pass http://strives.online:8088;
将请求代理到 8088 端口。
为什么 http 访问 443 就不行 https 访问 443 就可以呢
因为地址访问到了 443 端口,但是因为配置钟是
listen 443 ssl
,所以需要使用 https 访问。listen 443 ssl
:这个配置告诉 Nginx 在 443 端口上监听,并且要求使用 SSL/TLS 任何非加密的请求(即 HTTP 请求)都会被拒绝。
为什么 访问 https http 两个请求头不一样(难道不区分?), 433 端口一样 就会自动进去 433 这个 docker 容器呢? 进入容器是先根据端口吗?
是的,进入容器的过程主要是基于端口映射,与请求头无关。
端口映射
端口映射:Docker 使用端口映射将主机上的端口(如 80 或 443)转发到容器内的对应端口。
网络请求:当请求到达主机的某个端口时,Docker 会根据配置将请求转发到相应的容器。
协议处理
协议:HTTP 和 HTTPS 是不同的协议。虽然请求进入容器是基于端口映射,但处理请求的方式取决于容器内服务的配置。
Nginx 配置:如果 Nginx 配置了 listen 443 ssl;,它会期望接收到的是 HTTPS 请求,并进行 SSL/TLS 握手。
结论:
进入容器:是基于端口映射,与请求头无关。
请求处理:在容器内,服务会根据配置处理不同类型的请求(HTTP 或 HTTPS)。