前言
在当今互联网时代,安全性成为越来越重要的议题。随着网络攻击日益猖獗,保护数据和通信的安全性变得至关重要。在这种背景下,对于在 Docker 中运行 Nginx 是否需要使用 HTTPS 这一问题,我们需要考虑到网络安全的重要性以及 HTTPS 协议所提供的加密和认证功能。接下来,让我们深入探讨为什么在 Docker 中运行 Nginx 时使用 HTTPS 是至关重要的。
目录
一、实现 https
1. Docker中的Nginx服务为什么要启用HTTPS
在生产环境中,使用 HTTPS(HTTP over SSL/TLS)对 Docker 中的 Nginx 进行加密和安全传输是非常重要的,原因如下:
- 数据加密:HTTPS 使用 SSL/TLS 协议对数据进行加密传输,可以保护数据在传输过程中不被窃取或篡改,确保数据的机密性和完整性。
- 身份验证:HTTPS 可以验证服务器的身份,防止中间人攻击,确保用户连接的是正确的服务器,同时也可以通过客户端证书对客户端进行身份验证。
- 信任与安全:HTTPS 使用数字证书来验证服务器的身份,建立信任关系,减少恶意攻击的可能性,提高通信的安全性。
- 符合标准:现代网络安全标准和实践推荐使用 HTTPS 来保护 Web 应用程序,确保数据的安全性。
- SEO 和用户信任:搜索引擎(如 Google)更倾向于将采用 HTTPS 的网站排名更靠前,同时用户也更倾向于信任使用 HTTPS 的网站,提升用户体验和信任度。
2. HTTPS 单向认证过程
HTTPS证书认证的过程涉及以下步骤:
- 客户端发起连接:用户在浏览器中输入HTTPS网址,客户端(通常是浏览器)向服务器发起连接请求。
- 服务器返回证书:服务器收到连接请求后,会将自己的数字证书发送给客户端。证书包含了服务器的公钥、证书颁发机构(CA)的数字签名、有效期等信息。
- 客户端验证证书:客户端收到服务器的证书后,会验证证书的有效性。验证包括检查证书是否由受信任的证书颁发机构签发,证书是否在有效期内,以及证书中的域名是否与访问的域名匹配等。
- 客户端生成会话密钥:如果证书验证通过,客户端会生成一个随机的对称密钥(会话密钥)用于加密通信。
- 客户端用公钥加密会话密钥:客户端使用服务器的公钥(证书中包含的公钥)对会话密钥进行加密,然后发送给服务器。
- 服务器用私钥解密会话密钥:服务器收到客户端发送的加密的会话密钥后,使用自己的私钥(与证书中的公钥对应)进行解密。
- 建立安全连接:服务器和客户端现在都有了会话密钥,它们可以使用这个密钥来加密和解密通信内容,建立安全的加密连接。
- 安全通信:双方之间的通信现在是加密的,数据在传输过程中会被加密保护,确保安全性和隐私性。
通过这个过程,HTTPS证书认证确保了通信的安全性和数据的保密性,防止了中间人攻击和窃听等安全威胁。
3. 如何获取证书
- 在阿里云、华为云、腾讯云等云服务商那里申请一年有效期的免费证书或者购买证书
- 在本地使用 openssl、mkcert、cfssl、certbot(Let's Encrypt)的工具生成本地私钥证书
3.1 通过阿里云获取证书
https://www.aliyun.com/product/cas?userCode=r3yteowb
2. 通过 openssl 获取证书
生成ca证书:
(1)创建ca私钥
[root@localhost ~]# mkdir -p /lnmp/nginx/cert
[root@localhost ~]# cd /lnmp/nginx/cert/
[root@localhost cert]# openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
...........++
................................++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem: # 输入123456
Verifying - Enter pass phrase for ca-key.pem: # 输入123456
# openssl: OpenSSL 是一个开放源代码的加密工具包,提供了一系列加密算法和工具,用于安全通信、数据加密等操作。
# genrsa: 这个命令告诉 OpenSSL 生成一个 RSA 密钥对,包括公钥和私钥。
# -aes256: 这个选项指定生成的私钥要使用 AES 256 位加密算法进行加密。这样生成的私钥文件会被加密存储,需要输入密码才能解密使用。
# -out ca-key.pem: 这个选项指定生成的私钥保存到名为 ca-key.pem 的文件中。
# 4096: 这个参数指定生成的 RSA 密钥长度为 4096 位,这是一个比较安全的密钥长度。
使用 OpenSSL 生成一个带有 AES 256 位加密的 4096 位 RSA 私钥,并将其保存到名为 ca-key.pem 的文件中。生成的私钥文件将会被加密存储,需要输入密码才能解密和使用。
(2)创建ca证书
[root@localhost cert]# openssl req -new -x509 -days 1000 -key ca-key.pem -sha256 -subj "/CN=*" -out ca.pem
Enter pass phrase for ca-key.pem: # 输入123456
# openssl req: 这个命令告诉 OpenSSL 工具执行证书请求操作。
# -new: 这个选项表示生成一个新的证书请求。
# -x509: 这个选项指示生成自签名的 X.509 格式证书,而不是生成证书请求。
# -days 1000: 这个选项指定证书的有效期为 1000 天,即证书在签发后的有效期限。
# -key ca-key.pem: 这个选项指定使用之前生成的 ca-key.pem 文件中的私钥来签署证书。
# -sha256: 这个选项指定使用 SHA-256 算法来生成证书的摘要。
# -subj "/CN=*": 这个选项指定了证书的主题字段,其中 /CN=* 表示通用名称(Common Name)为通配符 *,表示这是一个通用的证书,而不是针对特定域名的。
# -out ca.pem: 这个选项指定生成的证书将保存到名为 ca.pem 的文件中。
使用 OpenSSL 工具生成一个自签名的 X.509 格式的数字证书,该证书的有效期为 1000 天,使用之前生成的私钥文件 ca-key.pem 进行签名,主题字段为通配符 *,并将生成的证书保存到名为 ca.pem 的文件中。
用 ca 证书签发 server 端证书:
(3)创建服务器私钥
[root@localhost cert]# openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
..............++
................................................................................................................................................++
e is 65537 (0x10001)
# openssl genrsa: 这个命令告诉 OpenSSL 工具生成一个 RSA 私钥。
# -out server-key.pem: 这个选项指定生成的私钥将保存到名为 server-key.pem 的文件中。
# 4096: 这个参数指定生成的 RSA 私钥的位数为 4096 位,这是一种常见的安全密钥长度,提供了较高的安全性。
使用 OpenSSL 工具生成一个 4096 位的 RSA 私钥,并将生成的私钥保存到名为 server-key.pem 的文件中。生成的私钥文件通常用于安全通信中,例如用于 HTTPS 连接中的服务器端认证。
(4)生成证书签名请求文件(csr文件)
[root@localhost cert]# openssl req -new -key server-key.pem -sha256 -subj "/CN=*" -out server.csr
# openssl req: 这个命令告诉 OpenSSL 工具执行证书请求操作。
# -new: 这个选项指示 OpenSSL 创建一个新的 CSR。
# -key server-key.pem: 这个选项指定要用于生成 CSR 的私钥文件,这里是 server-key.pem。
# -sha256: 这个选项指定要使用 SHA-256 算法进行摘要计算。
# -subj "/CN=*": 这个选项指定了 CSR 的主题信息,其中 /CN=* 表示 Common Name (通用名称)字段为通配符 *,通常用于生成通配符证书。
# -out server.csr: 这个选项指定生成的 CSR 将保存到名为 server.csr 的文件中。
使用 OpenSSL 工具基于指定的私钥文件 server-key.pem 创建一个新的 CSR,其中的 Common Name 字段为通配符 *,并使用 SHA-256 算法进行摘要计算,最后将生成的 CSR 保存到名为 server.csr 的文件中。CSR 通常用于向证书颁发机构(CA)申请数字证书。
(5)使用ca 证书与私钥证书签发服务端签名证书,输入 123456,(需要签名请求文件,ca 证书,ca 密钥)
[root@localhost cert]# openssl x509 -req -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -days 1000 -out server-cert.pem
Signature ok
subject=/CN=*
Getting CA Private Key
Enter pass phrase for ca-key.pem:
# openssl x509: 这个命令告诉 OpenSSL 工具执行证书相关的操作。
# -req: 这个选项表示输入的文件是一个证书请求 (CSR)。
# -sha256: 这个选项指定使用 SHA-256 算法进行摘要计算。
# -in server.csr: 这个选项指定要签署的证书请求文件为 server.csr。
# -CA ca.pem: 这个选项指定要用来签署证书的 CA (Certificate Authority) 的证书文件为 ca.pem。
# -CAkey ca-key.pem: 这个选项指定用于签署证书的 CA 的私钥文件为 ca-key.pem。
# -CAcreateserial: 这个选项告诉 OpenSSL 生成一个序列号文件,用于跟踪已签署证书的序列号。
# -days 1000: 这个选项指定生成的证书有效期为 1000 天。
# -out server-cert.pem: 这个选项指定生成的证书将保存到名为 server-cert.pem 的文件中。
在执行过程中的输出含义如下:
# Signature ok: 表示签名验证成功,证书签名操作正常。
# subject=/CN=*: 表示证书的主题信息为 Common Name (CN) 字段为通配符 *。
# Getting CA Private Key: 表示正在获取 CA 的私钥用于签署证书。
# Enter pass phrase for ca-key.pem: 提示输入 ca-key.pem 文件的密码短语,以便获取 CA 的私钥进行签署操作。
使用指定的 CA 证书和私钥对给定的证书请求进行签署,生成一个新的证书,并将该证书保存到名为 server-cert.pem 的文件中。
[root@localhost cert]# ls
ca-key.pem ca.pem ca.srl server-cert.pem server.csr server-key.pem
# ca-key.pem: 这是 CA (Certificate Authority) 的私钥文件,用于对证书请求进行签署以生成数字证书。
# ca.pem: 这是 CA 的证书文件,包含了 CA 的公钥和其他相关信息。
# ca.srl: 这是用于跟踪已签署证书的序列号文件,用于生成唯一的证书序列号。
# server-cert.pem: 这是使用 CA 签署后生成的服务器数字证书文件,用于在安全通信中进行身份验证。
# server.csr: 这是服务器证书签名请求 (CSR) 文件,包含了服务器的公钥和相关信息,用于向 CA 请求签发数字证书。
# server-key.pem: 这是服务器的私钥文件,用于与服务器证书一起进行安全通信和加密解密操作
二、nginx 镜像构建
1. 安装docker-20.10.17
systemctl stop firewalld.service
setenforce 0
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 安装所需的依赖
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 添加Docker官方仓库
# [root@localhost ~]#yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 正常后面还是用国内阿里源更合适
sudo yum makecache fast
# 更新Yum缓存
sudo yum install docker-ce-20.10.17 docker-ce-cli-20.10.17 containerd.io
# 安装Docker CE 20.10.17
systemctl enable --now docker
# 启动并开机自启Docker服务
docker --version
# 验证安装
2. 进入 nginx 工作目录
[root@localhost cert]# cd ..
[root@localhost nginx]# ls
cert
[root@localhost nginx]# docker pull nginx
[root@localhost nginx]# docker pull centos:7
[root@localhost nginx]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 7383c266ef25 8 days ago 188MB
centos 7 eeb6ee3f44bd 2 years ago 204MB
[root@localhost nginx]# ls
cert Dockerfile html nginx-1.24.0.tar.gz nginx.conf wordpress-4.9.4-zh_CN.tar.gz
[root@localhost nginx]# ls html/wordpress/
index.php wp-admin wp-content wp-load.php wp-signup.php
license.txt wp-blog-header.php wp-cron.php wp-login.php wp-trackback.php
readme.html wp-comments-post.php wp-includes wp-mail.php xmlrpc.php
wp-activate.php wp-config-sample.php wp-links-opml.php wp-settings.php
3. 编写 Dockerfile 文件
[root@localhost nginx]# vim Dockerfile
FROM centos:7 # 基于centOS:7镜像作为基础镜像
MAINTAINER nginx image <fql> # 指定镜像的维护者信息
RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make openssl openssl-devel
# yum安装必要的软件包至镜像;
RUN useradd -M -s /sbin/nologin nginx # 创建nginx的系统用户,且无法登录系统
ADD nginx-1.24.0.tar.gz /usr/local/src/ # 将nginx文件解压到/usr/local/src/目录下
WORKDIR /usr/local/src/nginx-1.24.0 # 工作目录切换
RUN ./configure \ # 配置、编译并安装Nginx,指定安装路径、用户、用户组以及使用了 with-http_sub_status_module 模块
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \ # 加载nginx_http_ssl_module模块,该模块是处理SSL/TLS连接所必需的
--with-http_stub_status_module && make -j 8 && make instal
ENV PATH /usr/local/nginx/sbin:$PATH # 将Nginx可执行文件路径添加到环境变量中
COPY cert/ /usr/local/nginx/cert/ # 将证书文件和相关的密钥文件复制镜像目录中
ADD nginx.conf /usr/local/nginx/conf/ # 将宿主机当前目录nginx.conf配置文件复制到镜像指定目录
#ADD wordpress-4.9.4-zh_CN.tar.gz /usr/local/nginx/html/
ADD html/ /usr/local/nginx/html/ # 将本地的html目录添加到镜像中的/usr/local/nginx/html/目录下
RUN chmod 777 -R /usr/local/nginx/html/ # 授权
EXPOSE 80 # 暴露容器的80端口,http
EXPOSE 443 # 暴露容器的443端口,https
VOLUME [ "/usr/local/nginx/html/" ] # 在Docker内创建挂载点
ENTRYPOINT [ "/usr/local/nginx/sbin/nginx", "-g", "daemon off;" ]
# 启动Nginx并以非守护进程方式运行
4. 准备 nginx.conf 文件
[root@localhost nginx]# egrep -v "^(.)*#(.)*$" nginx.conf | grep -v "^$"
# 从文件nginx.conf中过滤掉以#开头的注释行和空行,然后输出剩余的非注释非空行内容
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
charset utf-8;
location / {
root html;
index index.html index.php;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ~ \.php$ {
# 指定了匹配请求URI以.php结尾的条件,~表示使用正则表达式匹配
root html; # 查找文件的根目录为html
fastcgi_pass 172.19.0.30:9000;
# Nginx将把.php文件发送到172.19.0.30上的FastCGI服务器的9000端口
fastcgi_index index.php; # 当请求URI以/结尾时,Nginx应该使用的默认文件
fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;
# 这个参数告诉FastCGI服务器要执行的PHP脚本的路径。$fastcgi_script_name是一个FastCGI变量,代表请求的文件路径
include fastcgi_params; # 包含了一个外部文件fastcgi_params
}
}
# 根据请求的URI找到对应的PHP文件,将请求发送给FastCGI服务器进行处理,并设置一些FastCGI参数。这样可以实现在Nginx服务器上运行PHP脚本的功能。
server {
listen 443 ssl; # 指定Nginx监听443端口,并启用SSL/TLS加密
server_name www.fql.com; # 只有当请求的域名是www.fql.com时,这个服务器块才会生效
ssl_certificate /usr/local/nginx/cert/server-cert.pem;
#指定SSL证书文件的路径,用于加密传输中的证书验证。
ssl_certificate_key /usr/local/nginx/cert/server-key.pem;
# 指定SSL证书对应的私钥文件的路径,用于解密传输中的数据
ssl_session_timeout 5m; # 设置 SSL 会话超时时间为5分钟
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location ~ \.html$ {
root html;
index index.html index.htm;
}
}
}
# ssl_ciphers:指定可用的加密套件,这里设置了一组安全的加密套件,以确保安全的通信。
# ssl_protocols:指定支持的 SSL/TLS 协议版本,这里设置了支持 TLSv1、TLSv1.1 和 TLSv1.2。
# ssl_prefer_server_ciphers on;:指定是否优先使用服务器端的加密套件。
# location ~ \.html$ { ... }:这是一个 Nginx 的 location 块,用于匹配以 .html 结尾的请求。在这个块中,设置了请求的根目录为 html,并指定了默认的索引文件为 index.html 或 index.htm。
5. 生成镜像
[root@localhost nginx]# docker build -t nginx:centos .
[root@localhost nginx]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx centos 661cbccabf64 19 seconds ago 595MB
nginx latest 7383c266ef25 8 days ago 188MB
centos 7 eeb6ee3f44bd 2 years ago 204MB
6. 启动镜像容器
[root@localhost nginx]# docker run -itd --name n1 -v /lnmp/nginx/html/:/usr/local/nginx/html/ -p 80:80 -p 443:443 nginx:centos
33427c34e854811db1969a2d62e021b1e092387b5a3dcf3b4211589a942c16b9
[root@localhost nginx]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
33427c34e854 nginx:centos "/usr/local/nginx/sb…" 3 seconds ago Up 1 second 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp n1
7. 验证 nginx
查看目录:
[root@localhost nginx]# echo "welcom to nginx" > /lnmp/nginx/html/index.html
[root@localhost nginx]# tree /lnmp/nginx/ -L 2
/lnmp/nginx/
├── cert
│ ├── ca-key.pem
│ ├── ca.pem
│ ├── ca.srl
│ ├── server-cert.pem
│ ├── server.csr
│ └── server-key.pem
├── Dockerfile
├── html
│ ├── index.html
│ └── wordpress
├── nginx-1.24.0.tar.gz
├── nginx.conf
└── wordpress-4.9.4-zh_CN.tar.gz