本文章为原创非复制行为
前言
nginx是一个非常轻量化的工具,可以用来做文件服务器、反向代理服务器、负载均衡等,使用nginx作为文件服务器处理静态资源性能比同样常见的apache更高。在docker中部署nginx的好处是与宿主机、其他容器之间环境隔离,创建一个docker容器资源占用比虚拟机小很多,而且可以方便地修改官方镜像来定制自己的nginx镜像,便于迁移。文章中的系统为Centos7,Nginx版本为1.17.3
nginx作为文件服务器的一些问题
开启nginx目录浏览做文件服务器很简单只需要添加几行配置即可,但是这样不一定能满足所有人的需求。浏览器如果识别到了mime.types文件内定义的类型时,点击该类型文件是在浏览器中打开而不是下载。网上很多文章解决这个问题时直接在location中添加attachment附件方式,这样需要一个个设置特定结尾(扩展名)的文件,比较麻烦也不能覆盖所有结尾(扩展名)。
还有一种解决设置如下
location /download/ {
types { }
default_type application/octet-stream;
}
当Url路径中包含/download/时,MIME类型会被重置为application/octet-stream
这样设置有一些缺点:
-
对浏览目录进行美化例如fancyindex时,如果将美化主题的css文件放在浏览目录下它的MIME类型text/css会被重置为application/octet-stream不显示正确的版式,同时浏览器Console可以看到Resource interpreted as Stylesheet but transferred with MIME type application/octet-stream
- 重置为application/octet-stream类型不是对所有浏览器有效,ie内核的浏览器和edge浏览器(非Chromium内核)不能触发下载请求,添加attachment附件方式则均可。
配置
先从官方拉取一个nginx镜像
[root@ykxz ~]# docker pull nginx
创建nginx容器并绑定目录
docker持久化主要使用两种方式,这两种权限管理不同,可以自由选择,绑定配置文件目录或配置文件可以在宿主机修改,并且数据会一直存在宿主机即便删除容器
1.volume
创建nginx容器时生成相关的默认配置文件,这种方式只能绑定目录不能绑定文件,首先创建一个docker volume,它在宿主机的/var/lib/docker/volume/nginx_conf/_data目录
[root@ykxz ~]# docker volume create nginx_conf
然后将volume绑定到容器内目录/etc/nginx,创建容器时docker会把容器内目录/etc/nginx(生成的默认配置文件)拷贝到volume
创建例子:
- [root@ykxz ~]# docker run --name nginx_container --restart=always --net=host \
-e TZ="Asia/Shanghai" -v /etc/localtime:/etc/localtime:ro \
-v nginx_conf:/etc/nginx \
-d nginx
2.bind mounts
如果已经有了配置文件可以将配置文件放在/host/path中,创建容器时会覆盖容器内目录/etc/nginx,注意如果宿主机绑定的不是/或~/这样的路径,docker会视为第一种处理
创建例子:
- [root@ykxz ~]# docker run --name nginx_container --restart=always --net=host \
-e TZ="Asia/Shanghai" -v /etc/localtime:/etc/localtime:ro \
-v /docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro -v /docker/nginx/conf.d:/etc/nginx/conf.d \
-v /docker/nginx/logs:/var/log/nginx \
-d nginx
需要注意的是如果将宿主机上的目录/host/path绑定到容器内目录/etc/nginx,则创建nginx容器时会将/host/path目录覆盖容器内目录/etc/nginx,如果/host/path为空目录则一创建好容器启动就会报[emerg] open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)错误:容器内配置文件不存在已被空目录覆盖
如果没有配置文件但是想选择bind mounts方式绑定到宿主机上,官方配置教程先创建一个临时容器生成默认配置文件,然后将文件从容器拷贝到宿主机,再用这个文件持久化绑定
创建容器时的一些解释
--net=host 使用host网络模式,docker创建新容器时会使用默认的bridge,因为nginx容器时常要修改一些开放的端口,每次创建一个新nginx容器实在不是一件方便的事情,使用host模式需要在firewalld开放对应端口
-e TZ="Asia/Shanghai" 设置容器时区的环境变量,容器时区默认为UTC,会影响容器日志打印的时间
-v /etc/localtime:/etc/localtime:ro 将宿主机中的本地时间文件覆盖到容器,设置容器本地时间
修改配置文件开启目录浏览功能
我不建议直接修改配置文件目录/etc/nginx/下的nginx.conf文件,因为如果配置的站点多起来之后配置文件会显得特别冗长,应该在开启gzip传输压缩或者其他功能时再修改nginx.conf文件,nginx.conf文件已经有一行
include /etc/nginx/conf.d/*.conf
包含了同级目录conf.d下的所有以.conf结尾的配置文件,我们应该将新建的配置文件放在conf.d中,保持整洁
添加以下配置开启目录浏览功能:
autoindex on;
autoindex_exact_size off; #设置以MB、GB等单位显示文件大小
autoindex_localtime on; #设置显示目录或文件的时间属性
设置不下载请求结尾为xxx的特定文件(不区分大小写),这里设置的是mp4、mp3结尾,匹配mime.types文件内定义的类型,将在浏览器打开
set $flag 0;
if (-f $request_filename) {
set $flag 1;
}
if ($request_filename ~* \.(mp4|mp3)$) {
set $flag 0;
}
if ($flag = 1) {
add_header Content-Disposition attachment;
}
因为nginx不支持if的&&和||逻辑运算符和嵌套,所以定义一个flag变量判断请求的文件是否直接下载
以下是我的配置文件参考,可直接复制,必须修改的地方为
listen 7000; nginx监听的端口
server_name your.domain.com; 不使用域名访问可以删除
alias file_server/; 文件服务器目录,/不可以删除
# vim: ft=conf
server {
listen 7000;
server_name your.domain.com;
charset utf-8;
location / {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
alias file_server/;
set $flag 0;
if (-f $request_filename) {
set $flag 1;
}
if ($request_filename ~* \.(mp4|mp3)$) {
set $flag 0;
}
if ($flag = 1) {
add_header Content-Disposition attachment;
}
}
error_log logs/error_your.domain.com:7000.log error;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
配置文件的解释
- 开启目录浏览,顶层目录是与配置文件同级的file_server目录
- 请求的是文件而非目录且结尾不为mp4、mp3时添加attachment附件方式,保证所有浏览器都可以触发下载请求
最后一步,在firewalld开放对应端口并重启nginx容器
[root@ykxz ~]# firewall-cmd --permanent --add-port=7000/tcp
[root@ykxz ~]# firewall-cmd --reload
[root@ykxz ~]# docker restart nginx_container