Nginx 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务,因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名。在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
在微服务的体系之下,Nginx正在被越来越多的项目采用作为网关来使用,配合Lua做限流、熔断等控制。
下图为Nginx的反向代理结构图
(图片来自于https://www.nginx.cn/nginxchswhyuseit)
对于大多数使用者来说,Nginx只是一个静态文件服务器或者http请求转发器,它可以把静态文件的请求直接返回静态文件资源,把动态文件的请求转发给后台的处理程序。
查找 nginx image 镜像
docker search nginx
这里我们拉取官方的最新版本的镜像:
docker pull nginx:latest
docker images
我们先启动一个简单的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"
# 注:两者不在同一目录下。
打印配置文件内容到屏幕上
cat nginx.conf
conf.d是一个文件夹,里面存放着default.conf
cd到conf.d的文件夹下面,然后打印文件内容到屏幕上面
cat default.conf
我们可以从中知道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
firwall-cmd:是Linux提供的操作firewall的一个工具
firewall-cmd --query-port=8080/tcp
firewall-cmd --permanent --add-port=8080/tcp
重启防火墙(修改配置后要重启防火墙)
firewall-cmd --reload
再次查询已经变为yes
但是还是无法访问,还需要去服务器的控制台去开启防火墙,
如果是阿里云,还需要在安全组里面手动添加端口 ,配置可由那些IP访问。不然你防火墙开放了端口也是没用的(亲身经历)。
服务器控制台设置好了以后,就可以访问了
这里的访问是不安全的,可以通过添加SSL证书来使用HTTPS来访问。
宿主机的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部分)
或者尝试Let’s Encrypt来添加SSL
openssl生成证书的大致流程
(图片来自于https://blog.csdn.net/luo15242208310/article/details/108127638)
我们这里只生成server证书
生成服务端私钥(server.key),这里需要设置两遍密码:
openssl genrsa -des3 -out server.key 2048
openssl req -new -key server.key -out server.csr
参数设置,首先这里需要输入之前设置的密码,
然后需要输入如下的信息,大概填一下就可以了,反正是测试用的
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
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
可以参考 使用Openssl生成自签证书这篇博客,以下都是这位博主的内容,这位博主记录的很详细。
导入自签CA证书到操作系统
关于证书不安全的提示,是由于我们自签名的CA证书不是权威机构,操作系统不承认所导致,可以将我们自己的CA安装到操作系统中
在windows系统可通过运行certmgr.msc来查看本地已安装证书:
在导入ca证书后,浏览器仍提示"不安全"
设置证书"使用者可选名称SAN"
查询相关资料后发现,新的chrome浏览器需要为自签证书设置SAN(使用者可选名称,subject alternative name)
关于openssl设置SAN可以参考:使用openssl为ssl证书增加“使用者备用名称(DNS)”
我在学习ssl阶段使用的openssl命令,后续操作的时候都使用xca(一个生成证书的图形化工具),在xca中设置SAN如下:
重新生成证书、重新加载配置后,可以发现此时浏览器不再报"不安全"了,同时查看证书可以发现"使用者可选名称"已被添加
给域名添加SSL也可以(更加方便),并且腾讯云,阿里云之类的还会帮你生成对应域名的SSL,你下载下来,拷贝到上面ssl/文件,然后修改配置文件就行
我这里是腾讯云,直接去腾讯云搜索框里面搜索SSL证书,然后申请证书
填写信息,证书绑定的域名(我这个域名已经解析到了服务器地址,是部署nginx的服务器,千万别搞错了,还是要通过域名去访问nginx服务的)
一系列的填写信息后就可以下载证书了
下载Nginx的证书
将下载下来的文件使用xftp软件拷贝到服务器挂载的文件夹下面,也就是/usr/local/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端口是默认的,所以可以省略)
对于每一个不同的子域名,都需要去申请一个ssl证书。
比如说mail.xt.com,需要去申请一个ssl证书,对于www.xt.com,还需要去申请一个新的ssl证书。
那么能不能申请一个通配的证书去适配一个主域名下的所有子域名呢。
有的,花钱。比如你可以申请一个*.xt.com的证书,那样所有子域名就都能用这个证书了。
我的nginx的证书如下:一个域名一个证书
CSDN的SSL证书:
在服务器上安装部署 SSL 证书后,使用 HTTPS 协议访问网站,页面加载缓慢、空白或提示 “无法访问”。
服务器防火墙未开启443端口:若您的服务器防火墙未开启443端口,将导致您无法使用 HTTPS 正常访问您网站,请开启服务器443端口后,再进行尝试。
安全组未开启:安全组是一种虚拟防火墙,具备有状态的数据包过滤功能,用于厂商设置云服务器、负载均衡、云数据库等实例的网络访问控制,控制实例级别的出入流量,是重要的网络安全隔离手段,默认情况下为关闭状态。请开启服务器的安全组设置后,再进行尝试。
浏览器缓存污染:浏览器缓存可以节约网络资源加速浏览,通常情况下浏览器会对最近请求过的资源进行缓存。当访问者再次请求这个页面时,浏览器将可能会以已缓存信息进行展示。
配置文件未配置正确:服务器的 Web 服务配置文件未配置正确,导致网站无法正确处理请求导致网站无法访问。
服务器防火墙未开启443端口
若您使用的是腾讯云的云服务器(CVM),您无需进行该项设置,云服务器(CVM)默认为开启状态,建议您检查 安全组是否开启。
若您使用的是腾讯云轻量应用服务器(Lighthouse),请参考 管理防火墙 开启443端口设置。
若您使用的是其他云厂商云服务器,请咨询您的云厂商。
安全组未开启
若您使用的是腾讯云的云服务器,请参考 添加安全组规则 开启443端口。
若您使用的是腾讯云轻量应用服务器(Lighthouse),则无该功能设置,建议您检查 防火墙是否开启443端口。
若您使用的是其他云厂商云服务器,请咨询您的云厂商是否有该策略,如有该策略,咨询如何开启443端口;如无该策略,建议您检查 防火墙是否开启443端口。不过我这里不同,我是使用宿主机映射的nginx容器的443端口,而容器内的端口都是默认开放的,所以我只需要打开宿主机的442端口
浏览器缓存污染
请清除您的浏览器缓存或使用其他浏览器进行访问测试。
配置文件未配置正确
请您检查配置文件是否正确,您可以参考对应的部署文档进行检查或在 云市场 购买证书部署服务。
(写博客主要是对自己学习的归纳整理,资料大部分来源于书籍、网络资料和自己的实践,整理不易,但是难免有不足之处,如有错误,请大家评论区批评指正。同时感谢广大博主和广大作者辛苦整理出来的资源和分享的知识。)