一个使用 Go 编写的对象存储目录浏览系统,界面风格参考 h5ai。 可以浏览 S3 兼容对象存储(AWS S3、阿里云 OSS、腾讯云 COS、MinIO 等)中某个指定文件夹下的 全部目录和文件,并提供上传、下载、删除等基础功能。
- 目录浏览:h5ai 风格的文件列表(图标、大小、修改时间、面包屑导航),文件夹优先排序, 支持深色模式,仅浏览配置的根前缀(文件夹)内的内容
- 文件操作:
- 上传:按钮选择或拖拽到页面(支持拖拽整个文件夹,自动保留目录结构), 多文件、带进度条,服务端流式转发不落盘,大文件自动分片
- 下载:服务端流式代理,无需暴露存储凭证或桶权限
- 删除:单个删除或勾选批量删除,文件夹递归删除
- 重命名(仅管理员):文件与文件夹均可改名,文件夹递归搬迁其下全部内容
- 新建文件夹
- 邮件验证码登录:无密码,输入邮箱 → 收取 6 位验证码 → 登录;
验证码 10 分钟有效、一次性、限制重发频率与尝试次数;会话为 HMAC 签名令牌。
配置默认邮箱域名后,用户可只填邮箱名(如
zhangsan)登录,系统自动补全为zhangsan@默认域;该域名不会出现在登录页,用户登录成功前不会被暴露 - 目录级权限:可把根目录下的一级目录设为只读 —— 普通用户仅能浏览与下载, 上传、删除、新建文件夹仅管理员可操作(含其所有子目录,服务端强制校验); 重命名无论目录是否只读都仅管理员可用
- 控制台(仅管理员):
- 对象存储配置:Endpoint、Region、AK/SK、Bucket、根目录前缀、Path-Style 寻址、 自签名证书兼容(跳过 TLS 校验),可在线测试连接
- SMTP 配置:服务器、端口、加密方式(SSL / STARTTLS / 无)、账号密码、发件人、 自签名证书兼容,可发送测试邮件;认证机制按服务器通告自动选择(PLAIN / LOGIN / CRAM-MD5), 25 端口明文连接亦可认证
- 登录权限:管理员邮箱、允许登录的邮箱(支持
*@example.com通配)、会话有效期、 默认邮箱域名 - 目录权限:把根目录下的一级目录设为只读
- 公告栏:公告内容、展示样式(提示/警示/紧急)、是否允许用户关闭
- 审计日志:查询页面 + rsyslog 外发配置(UDP/TCP、Tag、Facility),可发送测试消息
- 公告栏:以条带形式展示在登录后页面顶部,适合发布维护通知等信息; 三种醒目程度可选,可设为允许用户关闭(公告内容变更后会重新展示)
- 操作审计:记录每位用户的文件下载、上传、删除、重命名操作
(含时间、用户、路径、来源 IP、结果);持久化于数据目录
audit.log(JSON Lines), 并可通过 syslog 协议(RFC 3164,消息体为 JSON)实时外发到 rsyslog 服务器
内网/无外网环境部署请参阅 离线部署安装手册。
sudo ./install.sh # 安装或升级,注册 systemd 服务并启动
sudo ./install.sh --port 9090 # 指定监听端口
sudo ./install.sh uninstall # 卸载(--purge 连同数据目录一起删除)脚本会自动定位二进制(脚本同目录的 goweb / goweb-linux-<arch>,或 --binary 指定;
都没有且装了 Go 时从源码现场构建),安装到 /opt/goweb,以 nobody 用户注册 systemd
服务并完成健康检查。重复运行即为升级(自动备份旧版本为 goweb.bak,配置沿用)。
无 systemd 的环境会仅安装文件并给出手动启动命令。
采用多实例方式实现租户隔离:每个租户一个完全独立的实例(独立端口、配置、 S3/SMTP 凭证、管理员、会话密钥与审计日志),互不影响:
sudo ./install.sh --name tenant-a --port 9081 # 租户 A(服务名 goweb-tenant-a)
sudo ./install.sh --name tenant-b --port 9082 # 租户 B(服务名 goweb-tenant-b)
sudo ./install.sh uninstall --name tenant-a # 卸载某个租户每个实例安装在 /opt/goweb-<name>,各自访问 http://IP:端口/console 独立完成初始化。
升级某个租户:重新运行对应的安装命令即可。
前置 Nginx 按域名分发(每个租户一个域名,Cookie 天然按域隔离):
server {
listen 80;
server_name files-a.example.com;
location / { proxy_pass http://127.0.0.1:9081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
}
server {
listen 80;
server_name files-b.example.com;
location / { proxy_pass http://127.0.0.1:9082; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
}生产环境建议参照上文 Nginx 示例补充 HTTPS 与上传相关参数
(client_max_body_size、proxy_request_buffering off、超时)。
go build -o goweb .
./goweb默认监听 :8080,数据(配置文件、签名密钥)保存在 ./data/ 目录。
首次运行处于「初始化模式」:访问 http://localhost:8080/console(此时无需登录),
依次配置对象存储、SMTP,并在「登录权限」中填入管理员邮箱。保存管理员邮箱后系统即启用鉴权,
之后所有页面都需要邮箱验证码登录,控制台仅管理员可见。
生产环境建议用 systemd 常驻运行(在线与离线部署均适用),以 nobody 用户运行:
sudo mkdir -p /opt/goweb/data
sudo cp goweb /opt/goweb/goweb && sudo chmod +x /opt/goweb/goweb
sudo chown -R nobody /opt/goweb/data
sudo tee /etc/systemd/system/goweb.service > /dev/null <<'EOF'
[Unit]
Description=GoWeb S3/OSS 目录浏览
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=nobody
WorkingDirectory=/opt/goweb
Environment=GOWEB_LISTEN=:8080
Environment=GOWEB_DATA_DIR=/opt/goweb/data
ExecStart=/opt/goweb/goweb
Restart=on-failure
RestartSec=3
# 安全加固(可选)
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/opt/goweb/data
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now goweb
sudo systemctl status goweb # 查看运行状态
journalctl -u goweb -f # 跟踪日志docker build -t goweb .
docker run -d -p 8080:8080 -v goweb-data:/app/data goweb| 参数 | 说明 |
|---|---|
--ignore-email |
不通过 SMTP 投递,登录验证码直接打印到服务端控制台,登录流程其余环节不变 |
-v, --version |
显示版本 |
-h, --help |
显示帮助 |
--ignore-email 适合尚未配置邮件服务的内网环境与排障:
./goweb --ignore-email
# 2026/01/01 10:00:00 [ignore-email] zhangsan@test.com 的登录验证码: 123456(10 分钟内有效)注意:开启后任何能看到本进程日志(含
journalctl)的人都能登录任意被允许的邮箱, 启动时会打印醒目告警,请勿用于生产环境。systemd 部署可在服务文件的ExecStart=/opt/goweb/goweb后追加该参数。
| 变量 | 默认值 | 说明 |
|---|---|---|
GOWEB_LISTEN |
:8080 |
监听地址 |
GOWEB_DATA_DIR |
data |
数据目录(配置与密钥) |
GOWEB_DEBUG_CODE |
关闭 | 设为 1 时,邮件发送失败会把验证码打印到日志(仅供调试,生产环境勿开) |
| 服务 | Endpoint | Path-Style |
|---|---|---|
| AWS S3 | 留空(填写 Region 即可) | 否 |
| 阿里云 OSS | https://oss-cn-hangzhou.aliyuncs.com |
否 |
| 腾讯云 COS | https://cos.ap-guangzhou.myqcloud.com |
否 |
| MinIO | http://your-minio:9000 |
是 |
main.go 入口
internal/config/ 配置加载/保存(data/config.json,控制台在线修改)
internal/audit/ 操作审计:本地 JSONL + 内存缓冲 + syslog(rsyslog) 外发
internal/auth/ 邮箱验证码与会话令牌
internal/mailer/ SMTP 邮件发送
internal/storage/ S3 兼容存储的列目录/上传/下载/删除/重命名
internal/server/ HTTP 路由、鉴权中间件与各页面/接口处理
web/ 内嵌的模板与静态资源(html/template + 原生 JS)
go test ./...存储层使用 gofakes3 内存 S3 服务做端到端测试, 覆盖列目录、上传、下载、递归删除、重命名与根前缀隔离。
- 所有文件操作接口都要求登录,路径经过校验(拒绝
..、空段等),并被限制在配置的根前缀内 - 管理员功能(控制台各页面与接口、重命名等)对非管理员不可见:统一由中间件 返回与未知路由逐字一致的 404,而非 403 —— 不暴露端点的存在,也不给探测者 可枚举的目标;被拒绝的请求会记入服务端日志供管理员追溯,日志区分 「未登录」「会话令牌无效或已过期」「已登录的普通用户」三种身份
- 反向代理透传的
X-Forwarded-For由客户端可控,只在其首个地址能解析为 IP 时才采信,否则回退到真实连接地址——防止伪造的头部污染日志与审计记录 - 邮箱输入在提交阶段严格校验:本地部分只放行字母、数字与
.-_, 域名只放行字母、数字与-.;? ! = # & +、引号、尖括号、空格 以及任何控制字符(含\r\n\t)一律拒绝,绝不交给邮件投递系统。 邮件层另有一道防线,拒绝收件人/发件人/主题中的换行,杜绝邮件头注入 - 未登录用户请求验证码时返回统一提示,不泄露邮箱是否在允许名单中; 重发限流对名单内外的邮箱一视同仁,避免通过“发送过于频繁”枚举允许名单
- 默认邮箱域名仅存于服务端配置:登录页、前端脚本与任何未鉴权响应都不包含该域名, 邮箱名的补全在服务端完成
- 会话 Cookie 为
HttpOnly+SameSite=Lax;HTTPS 下自动携带Secure标记(建议生产环境置于 反向代理后启用 HTTPS) - AK/SK 与 SMTP 密码保存在服务端
data/config.json(权限 0600),控制台页面不回显密文