天天看点

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

Nginx简单介绍

Nginx 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务,因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名。在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

优点

  • 在性能上,Nginx 是一个很强大的高性能Web和反向代理服务,采用C进行编写,在连接高并发的情况下,能够支持高达 5万个并发连接数的响应,并且cpu、内存等资源消耗却非常低,运行非常稳定。
  • Nginx选择了 epoll and kqueue作为IO模型。Nginx以事件驱动的方式编写,所以有非常好的性能。
  • 在功能上,Nginx是优秀的代理服务器和负载均衡服务器;
  • 在安装配置上,Nginx安装简单、配置灵活。
  • Nginx支持热部署,启动速度特别快,还可以在不间断服务的情况下对软件版本或配置进行升级,即使运行数月也无需重新启动。

在微服务的体系之下,Nginx正在被越来越多的项目采用作为网关来使用,配合Lua做限流、熔断等控制。

下图为Nginx的反向代理结构图

(图片来自于https://www.nginx.cn/nginxchswhyuseit)

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

对于大多数使用者来说,Nginx只是一个静态文件服务器或者http请求转发器,它可以把静态文件的请求直接返回静态文件资源,把动态文件的请求转发给后台的处理程序。

应用场景

  • http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
  • 虚拟主机。可以实现在一台服务器虚拟出多个网站。
  • 反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。

Docker 安装部署Nginx

查找 nginx image 镜像

docker search nginx      

在镜像仓库里面,有如下镜像。

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

拉取nginx镜像

这里我们拉取官方的最新版本的镜像:

docker pull nginx:latest      
【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

查看本地镜像

docker images      
【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

查看nginx文件大致结构

我们先启动一个简单的nginx容器,好进去看看他的配置文件结构是怎样的,然后将这些文件挂载出来

启动nginx

启动一个简单的nginx

docker run -itd --name nginx  nginx      

进入docker的nginx容器

docker exec -it nginx /bin/bash      

确定进入容器内部后,用下面两个命令查找nginx的配置文件在哪:

# 查找nginx配置文件default.conf 
# 这个在/etc/nginx/conf.d/default.conf
find / -name "default.conf"

# 查找nginx配置文件nginx.conf 
# 这个在/etc/nginx/nginx.conf
find / -name "nginx.conf"
# 注:两者不在同一目录下。      
【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

进入到/etc/nginx 的文件夹下面

打印配置文件内容到屏幕上

cat nginx.conf      
【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

conf.d是一个文件夹,里面存放着default.conf

cd到conf.d的文件夹下面,然后打印文件内容到屏幕上面

cat default.conf      
【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

我们可以从中知道nginx的配置的一些信息(比如日志文件夹的位置)

退出容器

exit      

创建本地文件夹

以便于容器挂载,我在宿主机的/usr/local文件夹下面部署

mkdir -p /usr/local/nginx/html
mkdir -p /usr/local/nginx/config
mkdir -p /usr/local/nginx/config/conf.d
mkdir -p /usr/local/nginx/logs
mkdir -p /usr/local/nginx/ssl      

递归赋予这个文件夹的读写执行权限

chmod -R 777 /usr/local/nginx      

使用docker的cp命令把这两个配置文件复制到刚刚建好的目录下(容器需要成功构建成功才能cp出来,容器关闭了也可以cp出来):

把docker内的default.conf复制到外部

docker cp nginx:/etc/nginx/conf.d/default.conf /usr/local/nginx/config/conf.d/default.conf      

把docker内的nginx.conf复制到外部

docker cp nginx:/etc/nginx/nginx.conf /usr/local/nginx/config/nginx.conf      

将html文件也移动到外面

注意:docker 挂载文件夹的时候,如果本来镜像里面就有这些文件,必须移动到宿主机的挂载文件夹下面(根据我的实验好像不会自动拷贝到宿主机上面),而如果是docker 启动运行生成的文件可以不用放到宿主机外面,这里的html文件应该是压缩在nginx镜像里面的,所以这里必须要移动到外面

docker cp nginx:/usr/share/nginx/html/50x.html /usr/local/nginx/html/50x.html 
docker cp nginx:/usr/share/nginx/html/index.html /usr/local/nginx/html/index.html      

nginx.conf配置文件 (配置nginx的一些信息)

#运行nginx的用户
user  nginx;
#启动进程设置成和CPU数量相等
worker_processes  1;

#全局错误日志及PID文件的位置
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

#工作模式及连接数上限
events {
        #单个后台work进程最大并发数设置为1024
    worker_connections  1024;
}


http {
        #设定mime类型
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

        #设定日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

        #设置连接超时的事件
    keepalive_timeout  65;

        #开启GZIP压缩
    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}      

可以看到最后一行还要包含另一个配置文件conf.d/default.conf,用来配置server字段

default.conf(这里主要配置server)

server {
    listen    80;       #侦听80端口,如果强制所有的访问都必须是HTTPs的,这行需要注销掉
    listen  [::]:80;
    server_name  localhost;             #域名

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

        # 定义首页索引目录和名称,nginx的默认首页的html文件,这个html可以自己定义一个,任意的都可以。
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #定义错误提示页面
    #error_page  404              /404.html;

    #重定向错误页面到 /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}      

这个时候直接通过IP地址就可以访问nginx定义的这个html文件了。但是这个时候的访问只是http的,https的访问还是不行的,需要添加证书到nginx服务器。

停止先前创建运行的容器nginx

docker stop nginx      

删除容器nginx

docker rm nginx      

运行挂载到宿主机的容器

带着挂载文件的命令启动nginx:(必须删除前面的,因为不仅名称冲突,端口号也冲突,不过你可以创建名称不同,监听端口不同的多个nginx服务器)

docker run -itd \
        --name nginx \
        -p 442:443\
        -p 8080:80 \
        -v /usr/local/nginx/html:/usr/share/nginx/html \
        -v /usr/local/nginx/config/nginx.conf:/etc/nginx/nginx.conf \
        -v /usr/local/nginx/config/conf.d/default.conf:/etc/nginx/conf.d/default.conf \
        -v /usr/local/nginx/logs:/var/log/nginx \
        -v /usr/local/nginx/ssl:/ssl \
        nginx      

参数说明:

–name nginx:容器名称。

-p 80:80: 端口进行映射,将本地 8080 端口映射到容器内部的 80 端口。

-itd 是docker run 的参数,等价于 -i -t -d 的结合,具体说明可以docker run --help 查看

-v表示挂载的文件,-v [该文件在容器外部的位置]:[该文件在容器内部的位置]

查看正在运行的容器

docker ps -a      
【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

查询nginx端口8080是否开放(宿主机)

firwall-cmd:是Linux提供的操作firewall的一个工具

firewall-cmd --query-port=8080/tcp      

答案是no

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

对外开放这个端口

firewall-cmd --permanent --add-port=8080/tcp      

重启防火墙(修改配置后要重启防火墙)

firewall-cmd --reload      

再次查询已经变为yes

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

但是还是无法访问,还需要去服务器的控制台去开启防火墙,

如果是阿里云,还需要在安全组里面手动添加端口 ,配置可由那些IP访问。不然你防火墙开放了端口也是没用的(亲身经历)。

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

服务器控制台设置好了以后,就可以访问了

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

这里的访问是不安全的,可以通过添加SSL证书来使用HTTPS来访问。

查询nginx端口442是否开放(宿主机)

宿主机的442端口映射到了nginx容器的443端口

firwall-cmd:是Linux提供的操作firewall的一个工具

firewall-cmd --query-port=442/tcp      

对外开放这个端口

如果上一条命令的答案是no,那么久对外开放这个442端口

firewall-cmd --permanent --add-port=442/tcp      

重启防火墙(修改配置后要重启防火墙)

firewall-cmd --reload      

同样的去服务器的控制台去开启防火墙,如果是阿里云,还需要在安全组里面手动添加端口 ,配置可由那些IP访问。

openssl添加SSL,使之可以安全访问(不推荐)

openssl生成的证书浏览器不认,还要一系列步骤很麻烦

我这里谨做个记录(大家可以跳转到给购买域名添加SSL部分)

或者尝试Let’s Encrypt来添加SSL

openssl生成证书的大致流程

(图片来自于javascript:void(0))

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

我们这里只生成server证书

生成服务端私钥(server.key),这里需要设置两遍密码:

openssl genrsa -des3 -out server.key 2048      
【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

生成服务端证书签名请求(server.csr)

openssl req -new -key server.key -out server.csr      

参数设置,首先这里需要输入之前设置的密码,

然后需要输入如下的信息,大概填一下就可以了,反正是测试用的

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

nginx启动的时候需要输入server.key的密码,解决办法是可以使用原key来生成解密后的key,并以解密后的key来代替(这里也要求输入之前设置的密码):

openssl rsa -in server.key -out server_nopwd.key      

生成服务端证书(server.cert)

openssl x509 -req -days 365 -in server.csr -signkey server_nopwd.key -out server.crt      

完成这一步之后就得到了我们需要的证书文件和私钥了

server.crt

server_nopwd.key

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

配置nginx服务器,支持https访问

server.crt 和server_nopwd.key文件放到我们预先创建的SSL文件夹下,我这里是在SSL文件夹下生成的,所以不用移动

修改配置文件default.conf,添加一个server

server {
    listen    443 ssl;
    #配置HTTPS的默认访问端口443。
    #如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
    #如果你使用Nginx 1.15.0及以上版本,请使用listen 443 ssl代替listen 443和ssl on。

    server_name  localhosst;             #证书绑定的域名

    # 增加ssl
    ssl_certificate /ssl/server.crt;
    ssl_certificate_key /ssl/server_nopwd.key;

    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;

    # 指定密码为openssl支持的格式
    ssl_protocols  SSLv2 SSLv3 TLSv1.2;

    ssl_ciphers  HIGH:!aNULL:!MD5;  # 密码加密方式
    ssl_prefer_server_ciphers  on;   # 依赖SSLv3和TLSv1协议的服务器密码将优先于客户端密码

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

        # 定义首页索引目录和名称,nginx的默认首页的html文件,这个html可以自己定义一个,任意的都可以。
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #定义错误提示页面
    #error_page  404              /404.html;

    #重定向错误页面到 /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}      
docker restart nginx      

访问HTTPS端口,如下所示。

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

Chrome中自签证书不安全问题

可以参考 ​​使用Openssl生成自签证书​​这篇博客,以下都是这位博主的内容,这位博主记录的很详细。

导入自签CA证书到操作系统

关于证书不安全的提示,是由于我们自签名的CA证书不是权威机构,操作系统不承认所导致,可以将我们自己的CA安装到操作系统中

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

在windows系统可通过运行certmgr.msc来查看本地已安装证书:

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

在导入ca证书后,浏览器仍提示"不安全"

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

设置证书"使用者可选名称SAN"

查询相关资料后发现,新的chrome浏览器需要为自签证书设置SAN(使用者可选名称,subject alternative name)

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

关于openssl设置SAN可以参考:​​使用openssl为ssl证书增加“使用者备用名称(DNS)”​​ 我在学习ssl阶段使用的openssl命令,后续操作的时候都使用xca(一个生成证书的图形化工具),在xca中设置SAN如下:

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

重新生成证书、重新加载配置后,可以发现此时浏览器不再报"不安全"了,同时查看证书可以发现"使用者可选名称"已被添加

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)
【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

给购买域名添加SSL

给域名添加SSL也可以(更加方便),并且腾讯云,阿里云之类的还会帮你生成对应域名的SSL,你下载下来,拷贝到上面ssl/文件,然后修改配置文件就行

服务器添加SSL

我这里是腾讯云,直接去腾讯云搜索框里面搜索SSL证书,然后申请证书

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

填写信息,证书绑定的域名(我这个域名已经解析到了服务器地址,是部署nginx的服务器,千万别搞错了,还是要通过域名去访问nginx服务的)

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

一系列的填写信息后就可以下载证书了

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

下载Nginx的证书

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

将下载下来的文件使用xftp软件拷贝到服务器挂载的文件夹下面,也就是/usr/local/nginx/ssl 下面

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

修改default.conf配置文件

server {
    listen    443 ssl;
    #配置HTTPS的默认访问端口443。
    #如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
    #如果你使用Nginx 1.15.0及以上版本,请使用listen 443 ssl代替listen 443和ssl on。

    server_name  www.xxx.club;             #证书绑定的域名(换成你自己的)

    # 增加ssl
    ssl_certificate /ssl/TecentServer.pem  #换成你自己的
    ssl_certificate_key /ssl/TecentServer.key;  #换成你自己的

    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;

    # 指定密码为openssl支持的格式
    ssl_protocols  SSLv2 SSLv3 TLSv1.2;

    ssl_ciphers  HIGH:!aNULL:!MD5;  # 密码加密方式
    ssl_prefer_server_ciphers  on;   # 依赖SSLv3和TLSv1协议的服务器密码将优先于客户端密码

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

        # 定义首页索引目录和名称,nginx的默认首页的html文件,这个html可以自己定义一个,任意的都可以。
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #定义错误提示页面
    #error_page  404              /404.html;

    #重定向错误页面到 /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}      

重新启动nginx容器服务

docker restart nginx      

如图所示,已经可以成功利用域名(HTTPS)来访问容器的nginx网页。

后面的端口号不能忘(因为域名只是对应到了IP地址,但是具体服务还是要通过端口号来找,但是80端口是默认的,所以可以省略)

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

关于ssl证书的坑

对于每一个不同的子域名,都需要去申请一个ssl证书。

比如说mail.xt.com,需要去申请一个ssl证书,对于www.xt.com,还需要去申请一个新的ssl证书。

那么能不能申请一个通配的证书去适配一个主域名下的所有子域名呢。

有的,花钱。比如你可以申请一个*.xt.com的证书,那样所有子域名就都能用这个证书了。

我的nginx的证书如下:一个域名一个证书

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

CSDN的SSL证书:

【Nginx】Nginx的简单介绍与Docker 安装部署Nginx(配置SSL安全访问)

添加SSL失败

在服务器上安装部署 SSL 证书后,使用 HTTPS 协议访问网站,页面加载缓慢、空白或提示 “无法访问”。

可能原因

服务器防火墙未开启443端口:若您的服务器防火墙未开启443端口,将导致您无法使用 HTTPS 正常访问您网站,请开启服务器443端口后,再进行尝试。

安全组未开启:安全组是一种虚拟防火墙,具备有状态的数据包过滤功能,用于厂商设置云服务器、负载均衡、云数据库等实例的网络访问控制,控制实例级别的出入流量,是重要的网络安全隔离手段,默认情况下为关闭状态。请开启服务器的安全组设置后,再进行尝试。

浏览器缓存污染:浏览器缓存可以节约网络资源加速浏览,通常情况下浏览器会对最近请求过的资源进行缓存。当访问者再次请求这个页面时,浏览器将可能会以已缓存信息进行展示。

配置文件未配置正确:服务器的 Web 服务配置文件未配置正确,导致网站无法正确处理请求导致网站无法访问。

解决办法

服务器防火墙未开启443端口

若您使用的是腾讯云的云服务器(CVM),您无需进行该项设置,云服务器(CVM)默认为开启状态,建议您检查 ​​​安全组是否开启​​​。

若您使用的是腾讯云轻量应用服务器(Lighthouse),请参考 ​​​管理防火墙​​​ 开启443端口设置。

若您使用的是其他云厂商云服务器,请咨询您的云厂商。

安全组未开启

若您使用的是腾讯云的云服务器,请参考 ​​​添加安全组规则​​​ 开启443端口。

若您使用的是腾讯云轻量应用服务器(Lighthouse),则无该功能设置,建议您检查 ​​​防火墙是否开启443端口​​​。

若您使用的是其他云厂商云服务器,请咨询您的云厂商是否有该策略,如有该策略,咨询如何开启443端口;如无该策略,建议您检查 ​​​防火墙是否开启443端口​​。不过我这里不同,我是使用宿主机映射的nginx容器的443端口,而容器内的端口都是默认开放的,所以我只需要打开宿主机的442端口

References:

  • ​​https://baike.baidu.com/item/nginx/3817705?fr=aladdin#1_1​​
  • ​​https://www.nginx.cn/nginxchswhyuseit​​
  • ​​https://www.runoob.com/docker/docker-install-nginx.html​​
  • ​​https://www.jianshu.com/p/5f9bd492f186​​
  • ​​https://cloud.tencent.com/document/product/400/53650​​

继续阅读