autoindex

  1. 1. nginx autoindex
    1. 1.1. 示例配置
  2. 2. flask autoindex 已不再更新
  3. 3. Apache(httpd)
  4. 4. python
  5. 5. Simple Web Server

搭建文件共享服务

nginx autoindex

Nginx 是一个高性能的 HTTP 和反向代理服务器,它也可以作为 IMAP/POP3 代理服务器。Nginx 以其稳定性、丰富的功能集、简单的配置和低资源消耗而闻名。

autoindex 是 Nginx 模块中的一个特性,它允许 Nginx 服务器自动生成目录索引页面。这意味着当用户访问一个目录而不是一个具体的文件时,Nginx 可以返回一个包含该目录下所有文件和子目录列表的页面。这对于网站管理员来说非常有用,因为它可以方便地展示文件结构,而无需手动创建索引页面。

以下是 Nginx 使用 autoindex 模块的一些基本配置示例:

  1. 启用 autoindex 模块
    在 Nginx 配置文件中,你需要启用 autoindex 模块。通常,这可以通过在 server 块中添加 autoindex on; 指令来实现。

    1
    2
    3
    4
    5
    6
    7
    server {
    listen 80;
    server_name example.com;
    root /path/to/your/directory;

    autoindex on;
    }
  2. 自定义索引页面
    你可以使用 autoindex_exact_sizeautoindex_localtime 指令来自定义索引页面的显示。autoindex_exact_size 允许显示文件的确切大小,而 autoindex_localtime 则使用本地时间而不是GMT时间。

    1
    2
    autoindex_exact_size off;
    autoindex_localtime on;
  3. 设置索引页面的格式
    你还可以使用 autoindex_format 指令来设置索引页面的格式,它可以是 htmljson

    1
    autoindex_format html;
  4. 添加自定义样式
    如果你想对自动生成的索引页面进行样式定制,你可以使用 autoindex_style 指令来指定一个 CSS 文件。

    1
    autoindex_style /path/to/your/style.css;
  5. 限制访问
    如果你只想让特定的用户或IP地址访问索引页面,你可以使用 allowdeny 指令来设置访问控制。

    1
    2
    3
    4
    5
    location / {
    allow 192.168.1.0/24;
    deny all;
    autoindex on;
    }

示例配置

  1. 配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# Generated by nginxconfig.io
# See nginxconfig.txt for the configuration share link

user nginx;
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;

# Load modules
include /etc/nginx/modules-enabled/*.conf;

events {
multi_accept on;
worker_connections 65535;
}

http {
charset utf-8;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
log_not_found off;
types_hash_max_size 2048;
types_hash_bucket_size 64;
client_max_body_size 16M;

# MIME
include mime.types;
default_type application/octet-stream;

# Logging
access_log off;
error_log /dev/null;

# Load configs
include /etc/nginx/conf.d/*.conf;

# 192.168.72.5
server {
listen 80;
listen [::]:80;
server_name yx.taimei.com;
root /usr/share/nginx/html;

# security headers
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: ws: wss: data: blob: 'unsafe-inline'; frame-ancestors 'self';" always;
add_header Permissions-Policy "interest-cohort=()" always;

# . files
location ~ /\.(?!well-known) {
deny all;
}

# logging
access_log /var/log/nginx/access.log combined buffer=512k flush=1m;
error_log /var/log/nginx/error.log warn;

# index.html fallback
location / {
try_files $uri $uri/ /index.html;
autoindex on;
autoindex_format html;
autoindex_exact_size on;
autoindex_localtime on;
add_after_body /.autoindex.html;
}

# favicon.ico
location = /favicon.ico {
log_not_found off;
}

# robots.txt
location = /robots.txt {
log_not_found off;
}

# assets, media
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
expires 7d;
}

# svg, fonts
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
add_header Access-Control-Allow-Origin "*";
expires 7d;
}
}
# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+;
}
  1. docker-compose
1
2
3
4
5
6
7
8
9
10
11
12
services:
web:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./www:/usr/share/nginx/html
ports:
- "80:80"
environment:
- NGINX_PORT=80
- NGINX_HOST=yx.taimei.com
restart: always
  1. 样式自定义.autoindex.html放在www目录下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<link rel="icon" href="https://file.trialos.com.cn/resources/8a8dbdbc90c1807401914aaa302f2f07.jpg" type="image/x-icon">
<style>
body > hr {
display: none;
}

.yq-row {
display: flex;
justify-content: flex-start;
align-items: center;
}

.yq-row > * {
flex: 1;
}

.yq-outer-box a {
color: #000;
padding: 10px 5px;
margin: 0 -5px;
white-space: nowrap;
overflow: hidden;
display: block;
width: 100%;
text-overflow: ellipsis;
text-decoration: none;
}

.yq-outer-box a::before {
display: inline-block;
vertical-align: middle;
margin-right: 10px;
width: 24px;
text-align: center;
line-height: 12px;
}

.yq-outer-box a.file::before {
content: url("data:image/svg+xml;utf8,<svg width='15' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M10 8C8.34 8 7 6.66 7 5V1H3c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V8h-4zM8 5c0 1.1.9 2 2 2h3.59L8 1.41V5zM3 0h5l7 7v9c0 1.66-1.34 3-3 3H3c-1.66 0-3-1.34-3-3V3c0-1.66 1.34-3 3-3z' fill='black'/></svg>");
}

.yq-outer-box a:hover {
text-decoration: underline;
}

.yq-outer-box a.folder::before {
content: url("data:image/svg+xml;utf8,<svg width='20' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M18.784 3.87a1.565 1.565 0 0 0-.565-.356V2.426c0-.648-.523-1.171-1.15-1.171H8.996L7.908.25A.89.89 0 0 0 7.302 0H2.094C1.445 0 .944.523.944 1.171v2.3c-.21.085-.398.21-.565.356a1.348 1.348 0 0 0-.377 1.004l.398 9.83C.42 15.393 1.048 16 1.8 16h15.583c.753 0 1.36-.586 1.4-1.339l.398-9.83c.021-.313-.125-.69-.397-.962zM1.843 3.41V1.191c0-.146.104-.272.25-.272H7.26l1.234 1.088c.083.042.167.104.293.104h8.282c.125 0 .25.126.25.272V3.41H1.844zm15.54 11.712H1.78a.47.47 0 0 1-.481-.46l-.397-9.83c0-.147.041-.252.125-.356a.504.504 0 0 1 .377-.147H17.78c.125 0 .272.063.377.147.083.083.125.209.125.334l-.418 9.83c-.021.272-.23.482-.481.482z' fill='black'/></svg>");
}

.yq-outer-box a.lambda::before {
content: url("data:image/svg+xml; utf8,<svg width='15' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M3.5 14.4354H5.31622L7.30541 9.81311H7.43514L8.65315 13.0797C9.05676 14.1643 9.55405 14.5 10.7 14.5C11.0171 14.5 11.291 14.4677 11.5 14.4032V13.1572C11.3847 13.1766 11.2622 13.2024 11.1541 13.2024C10.6351 13.2024 10.3829 13.0281 10.1595 12.4664L8.02613 7.07586C7.21171 5.01646 6.54865 4.5 5.11441 4.5C4.83333 4.5 4.62432 4.53228 4.37207 4.59038V5.83635C4.56667 5.81052 4.66036 5.79761 4.77568 5.79761C5.64775 5.79761 5.9 6.0042 6.4045 7.19852L6.64234 7.77954L3.5 14.4354Z' fill='black'/><rect x='0.5' y='0.5' width='14' height='18' rx='2.5' stroke='black'/></svg>");
}

.yq-outer-box a.img::before {
content: url("data:image/svg+xml;utf8,<svg width='16' height='19' viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='black' stroke-width='5' stroke-linecap='round' stroke-linejoin='round'><rect x='6' y='6' width='68' height='68' rx='5' ry='5'/><circle cx='24' cy='24' r='8'/><path d='M73 49L59 34 37 52m16 20L27 42 7 58'/></svg>");
}
</style>
<script>
function getClassName(filename) {
if (!filename) {
return 'file';
}
if (filename.endsWith('/')) {
return 'folder';
}
const array = filename.split('.');
let suffix = array[array.length - 1];
if (!suffix) {
return 'file';
}
suffix = suffix.toLowerCase();
const img = ['gif', 'jpg', 'png', 'svg', 'jpeg', 'bmp'];
if (img.includes(suffix)) {
return 'img';
}
const lambda = ['java', 'js', 'ts', 'go', 'c', 'cpp', 'cs', 'py', 'sh', 'swift', 'php', 'html', 'css', 'xml', 'json', 'yml', 'yaml', 'md', 'log', 'ini', 'conf', 'properties', 'cmd', 'bat'];
if (lambda.includes(suffix)) {
return 'lambda';
}
return 'file';
}

function formatDate(date, time) {
const mon = {
Jan: '01',
Feb: '02',
Mar: '03',
Apr: '04',
May: '05',
Jun: '06',
Jul: '07',
Aug: '08',
Sep: '09',
Oct: '10',
Nov: '11',
Dec: '12',
};
const [day, month, year] = date.split('-');
return `${year}-${mon[month]}-${day} ${time}`;
}

function formatSize(size) {
if (size === '-') {
return '';
}
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let s = Number(size);
for (const u of units) {
if (s < 1024) {
return s.toFixed(2) + ' ' + u;
}
s = s / 1024;
}
return s.toFixed(2) + ' ' + units[units.length - 1];
}

function change() {
const preElement = document.getElementsByTagName('pre')[0];
const preClassName = preElement.className;
if (preClassName) {
return;
}
const outerBox = document.createElement('div');
outerBox.classList.add('yq-outer-box');

let row;
preElement.childNodes.forEach((child) => {
if (child.nodeType === Node.ELEMENT_NODE) {
row = document.createElement('div');
row.classList.add('yq-row');
const name = document.createElement('a');
name.href = child.href;
name.innerText = child.text;
name.classList.add(getClassName(child.text));
row.appendChild(name);
outerBox.appendChild(row);
} else if (child.nodeType === Node.TEXT_NODE) {
const text = child.nodeValue.trim();
if (!text) {
return;
}
const textArray = text.split(' ').filter((item) => item.trim());
const lastModified = document.createElement('div');
lastModified.innerText = formatDate(textArray[0], textArray[1]);
lastModified.classList.add('last-modified');
row.appendChild(lastModified);
const size = document.createElement('div');
size.innerText = formatSize(textArray[2]);
size.classList.add('size');
row.appendChild(size);
}
});

document.body.removeChild(preElement);
document.body.appendChild(outerBox);
}

change();
</script>

flask autoindex 已不再更新

github:flask-autoindex

Apache(httpd)

1
2
3
4
5
6
7
8
9
10
services:
apache:
image: httpd:latest
container_name: apache_file_share
ports:
- "9080:80"
volumes:
- ./files:/usr/local/apache2/htdocs/files
- ./htpasswd:/usr/local/apache2/htdocs/.htpasswd
restart: always
1
docker-compose up -d

(可选)修改配置文件/usr/local/apache2/conf/httpd.conf

反注释掉

1
2
Include conf/extra/httpd-autoindex.conf
# 再次执行 docker-compose up -d

python

1
python -m http.server
  • docker-compose
1
2
3
4
5
6
7
8
9
services:
http-server:
image: python:3.12-slim
command: python -m http.server 8000
ports:
- "8000:8000"
volumes:
- ./share:/app
working_dir: /app

Simple Web Server

jdk18+

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.cong;

import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.SimpleFileServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {
public static void main(String[] args) throws IOException {
// 设置根目录路径
Path root = Paths.get("/Users/cong/IdeaProjects/http-server/src/main/resources/public");

// 创建 HTTP 服务器,监听端口 8000
HttpServer server = SimpleFileServer.createFileServer(new InetSocketAddress(8000), root, SimpleFileServer.OutputLevel.VERBOSE);

// 启动服务器
server.start();
System.out.println("Static file server started at http://localhost:8000/");
}
}