天天看点

使用 Docker 和 Nginx 实现简单目录索引服务

本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2018年12月16日 统计字数: 3548字 阅读时间: 8分钟阅读 本文链接: https://soulteary.com/2018/12/16/implement-a-simple-directory-indexing-service-using-docker-and-nginx.html

本文将会介绍如何使用 Docker、Node、JavaScript、Traefik 完成一个简单的目录索引服务,全部代码在 300 行以内。相关代码已开源至 GitHub ,文末有链接,感兴趣可以自取。

实现一个目录索引站点并不是什么难事,但是即便如此,需要考虑的事情也有很多,要实现非阻塞IO、要实现文件缓存、要实现SSL等等一系列稍微有些麻烦的事情,如何能在尽可能少编写代码的情况下,完成这个需求呢。

其实很简单,借助完善靠谱的开源项目们,本文最终实现例子效果如下。

使用 Docker 和 Nginx 实现简单目录索引服务

实现核心逻辑

说到 Web 目录索引服务,我们一般会想到的就是大名鼎鼎的 Nginx 或者它的竞品们了。而它其中一个默认模块便提供了这个目录列表的功能: ngx_http_autoindex_module。

这个模块十分简单,在此我就不过度展开,有兴趣可以翻阅 Nginx 官方文档,了解这个模块提供的几个简单的指令。

对某个路由下的页面开启 autoIndex 可以轻松实现列目录的功能,比如这样:

如果你简单使用上面的逻辑,你会得到一个黑底白字的页面,虽然能用,但是未免太过丑陋,查看生成文档源代码(由于代码高亮问题,使用 xpre 代替 pre):

这个时候一般会有两个方案对默认的界面进行美化:

编译一个支持定义模板的 Nginx 插件。

使用 ngx_http_addition_module 模块手动进行模板美化。

第一种方案需要额外编译,有一定的额外维护成本、以及后续升级改造的不稳定因素。我们选择第二种方式,比如将上面的逻辑改造为:

location / {

add_before_body /autoindex/header.html;

add_after_body /autoindex/footer.html;

}

<!doctype html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>小站</title>

<style>your code here</style>

</head>

<body><html>

<head><title>Index of /</title></head>

<body>

Index of /<hr><xpre><a rel="nofollow" href="../">../</a>

<a rel="nofollow" href="a/">a/</a> 16-Dec-2018 13:39 -

<a rel="nofollow" href="b/">b/</a> 16-Dec-2018 13:39 -

<a rel="nofollow" href="c/">c/</a> 16-Dec-2018 13:39 -

</xpre><hr></body>

</html>

<table><thead><tr><th width="40%">Name</th><th width="30%">Date</th><th width="10%">Size</th></tr></thead><tbody></tbody><tfoot><tr><th colspan="3"><a rel="nofollow" href="https://soulteary.com" target="_blank">Proudly Powered By Nginx, Design By @soulteary</a></th></tr></tfoot></table>

<script>your code here</script>

</body>

Index of /<xpre><a rel="nofollow" href="../">../</a>

</xpre>

var dataSets = document.getElementsByTagName('pre')[0].innerHTML.split('\n');

var directoryUp = false;

var tpl = '';

for (var i = 0, j = dataSets.length - 1; i < j; i++) {

var line = dataSets[i];

if (line.indexOf('../') === -1) {

line = line.match(/^(.*)\s+(\S+\s\S+)\s+(\S+)/);

tpl += '<tr>' +

'<td>' + line[1] + '</td>' +

'<td>' + '<span class="date" datetime="' + new Date(line[2]) + '">' + line[2] + '</span>' + '</td>' +

'<td>' + line[3] + '</td>' +

'</tr>';

} else {

if (location.pathname !== '/') directoryUp = true;

if (directoryUp) tpl = '<tr><td colspan="3"><a rel="nofollow" href="..">..</a></td></tr>' + tpl;

document.getElementsByTagName('tbody')[0].innerHTML = tpl;

timeago().render(document.querySelectorAll('.date'));

nginx:1.15.7-alpine

version: '3'

services:

nginx:

image: nginx:1.15.7-alpine

restart: always

labels:

"traefik.enable=true"

"traefik.port=80"

"traefik.frontend.rule=Host:demo.soulteary.com,demo.soulteary.io"

"traefik.frontend.entryPoints=https,http"

"traefik.frontend.headers.customResponseHeaders=Access-Control-Allow-Origin:*"

networks:

traefik

expose:

80

volumes:

./nginx.conf:/etc/nginx/nginx.conf

./mime.types:/etc/nginx/mime.types

./public:/app/public

./autoindex:/app/.autoindex

extra_hosts:

"demo.soulteary.com:127.0.0.1"

"demo.soulteary.io:127.0.0.1"

traefik:

external: true

docker-compose up --scale nginx=2