Files

15 KiB
Raw Permalink Blame History

初春图床 OneImg

现代化自托管图床系统,兼顾上传体验、存储灵活性与后台可控性。
基于 Vue 3 + Go 构建,适合个人站点、博客、团队内容管理和多存储备份场景。

Gitea 仓库 · 上游项目 · 问题反馈

功能特性 · 界面预览 · 快速开始 · 部署说明


项目简介

OneImg 是一个功能完整的自托管图床与图片管理系统。本仓库基于上游项目 onexru/oneimg,用于个人定制、功能扩展和持续维护;上游项目的许可证与版权信息请以其仓库为准。

当前仓库保留 OneImg 的核心能力,并结合实际部署需求持续扩展,例如 Gitea 集成、多存储同步、R2 直传、数据库 TLS 配置、初始密码安全处理,以及本地存储和外部存储访问的兼容性与安全性改进。具体变更以本仓库提交记录为准。

它的核心目标不只是「能传图」,而是将上传、管理、访问、同步和存储切换整合成一套顺手的完整工作流。

相比传统图床方案,OneImg 在以下几个维度上做了更深的设计:

  • 自托管可控:数据完全掌握在自己手中,避免平台绑定与服务关停风险
  • 多存储统一管理:同时接入本地磁盘、对象存储和第三方通道,一套界面管理所有存储后端
  • 链接稳定可迁移:图片 URL 可长期保持不变,底层存储随时切换或扩展,对访问方完全透明
  • 完整后台能力:用户体系、权限控制、标签分类、容量统计、系统配置一应俱全

适用场景:个人博客与技术站点图床、团队文档配图管理、需要数据可控的自托管图片服务、以及希望将本地存储与对象存储/Telegram/FTP/WebDAV 统一纳入管理的环境。


功能特性

上传体验

支持多种上传方式,覆盖日常内容生产的全部习惯:

  • Ctrl+V 剪贴板粘贴:截图后直接粘贴即传,无需额外操作
  • 拖拽上传:将图片拖入上传区域即可
  • 批量选择:一次选择多张图片,配合实时进度条
  • R2 直传:支持浏览器向 Cloudflare R2 直传,并在服务端完成校验与入库
  • URL 远程上传:输入图片链接,服务端拉取后入库
  • 支持格式:JPEG / PNG / GIF / WebP(按实际图片字节校验,不信任浏览器声明的 MIME)

存储架构

支持 6 种存储后端,可按需组合使用:

存储类型 说明
本地磁盘 默认存储,数据直接落盘
Cloudflare R2 独立存储类型,支持专用端点与 CDN、浏览器直传
S3 兼容 支持 SeaweedFS、MinIO、阿里云 OSS 等 S3 协议存储;默认使用 Path Style
FTP 传统 FTP 服务器
WebDAV 支持 Nextcloud、坚果云等 WebDAV 服务
Telegram 通过 Telegram Bot 将图片发送到频道/私聊

核心设计理念:

  • 稳定链接:每张图片拥有固定 URL,不因存储切换而改变
  • 访问源切换:不换链接即可切换实际读取的存储副本,方便在多个存储间调度
  • 多存储同步:本机与远程存储可协同工作,一张图可同时存在于多个存储后端
  • 故障自动回退:远程源停用时,已选该源的图片自动回退到本机读取,不中断服务、不删除文件

S3 存储默认启用 Path Style 请求(Endpoint/Bucket/Object),适用于 SeaweedFS、MinIO 以及通过反向代理暴露的自建 S3 服务。只有在服务明确要求虚拟主机风格(Bucket.Endpoint/Object)时, 才在存储管理中关闭「强制 Path Style」。旧存储配置未保存该字段时也会按 Path Style 运行。

安全机制

从登录到存储,多层防护组合使用:

  • POW 工作量证明登录:暴力破解成本指数级提升,有效抵御自动化攻击
  • AES-256-GCM 图片加密:支持全部存储后端,加密后的文件即使泄露也无法直接查看
  • Session 会话管理:超时自动失效,防止会话劫持
  • 密码 bcrypt 加密:拒绝明文存储,符合安全最佳实践
  • 配置加密:敏感配置项(如存储密钥)支持加密存储

如果启用了图片加密存储,请务必妥善保管 CONFIG_SECRET。更换或丢失该密钥会导致历史加密内容无法正常解密。

管理后台

提供完整的 Web 管理界面,所有操作集中在一处完成:

  • 图片管理:列表浏览、详情查看、标签分类、批量删除
  • 图库整理:创建文件夹、移动图片,并按标签筛选
  • 用户与权限:多用户体系,按角色与权限分配存储访问能力
  • 外部登录:支持 OIDC 与 CAS 单点登录
  • API 凭据:生成和管理 API Token,供外部程序调用上传接口
  • 存储管理:各存储后端状态监控、容量统计、同步状态追踪
  • 系统设置:全局配置、安全策略、上传限制等
  • 数据概览:仪表板实时展示上传量、存储用量等关键指标

界面设计

  • 深色 / 浅色主题无缝切换
  • 全响应式布局,移动端友好
  • 流畅过渡动画,操作反馈明确

界面预览

现代化后台布局,覆盖上传、图库、标签、存储管理、用户权限与系统设置等核心场景。


快速开始

几分钟即可跑起来,适合先本地体验,再逐步接入对象存储或远程存储。

Docker Compose

git clone https://git.bytevibe.dev/gary/oneimg.git
cd oneimg
cp .env.example .env
docker compose up -d
docker compose exec oneimg cat /app/data/.initial_admin_password

默认直连模式只在本机发布 127.0.0.1:8080,访问 http://127.0.0.1:8080。 使用 Traefik 时,在 .env 设置 TRAEFIK_ENABLED=1、TRAEFIK_HOST 和公网 APP_URL,并确认 Traefik 与 oneImg 共用 TRAEFIK_NETWORK 指定的外部网络(默认 frontend)。例如网络尚未创建时先执行 docker network create frontend,然后运行 docker compose up -d。Traefik 模式不会发布宿主机端口;TRUSTED_PROXIES 应设为该网络中 Traefik 的 IP 或子网。示例默认挂载 real-ip@file,需在 Traefik file provider 中定义;没有该中间件时移除覆盖文件中的对应 label。关闭 Traefik 时清空 TRAEFIK_ENABLED 再运行 docker compose up -d。

Gitea 容器镜像

仓库内的 Gitea Actions 工作流在推送版本标签(v*)或手动触发时构建 linux/amd64 和 linux/arm64 镜像,并推送到 Gitea Container Registry。请在仓库 Actions Secrets 中设置:

  • REGISTRY_USERNAME:可推送镜像的 Gitea 用户名
  • REGISTRY_TOKEN:该用户的包写入令牌

默认注册表为 git.bytevibe.dev。如需覆盖,设置仓库 Actions Variable GITEA_REGISTRY。 镜像标签为 latest 和触发构建的版本标签,例如 git.bytevibe.dev/gary/oneimg:latest。

启动后访问 http://127.0.0.1:8080

Docker 直接运行

docker run -d \
  --name oneimg \
  -p 8080:8080 \
  -e APP_URL=https://img.example.com \
  -v /data/oneimg:/app/data \
  -v /data/oneimg-uploads:/app/uploads \
  --restart unless-stopped \
  git.bytevibe.dev/gary/oneimg:latest

# 查看首次启动生成的随机管理员密码
docker exec oneimg cat /app/data/.initial_admin_password

初始账号与密码

账号:admin(由 DEFAULT_USER 决定)
密码:首次启动自动生成,见 data/.initial_admin_password

默认 DEFAULT_PASS 留空时,初始管理员密码按以下规则生成:

DEFAULT_PASS 行为
留空(推荐) 仅在数据库中还没有任何用户时,生成 43 字符随机密码写入 data/.initial_admin_password(权限 0600),不打印到日志
非空 直接使用该值作为初始管理员密码
  • 该文件只在首次创建管理员时写入;之后重启不会覆盖,也不会重置已有账号的密码。
  • 密码不会出现在启动日志里,必须读取该文件获取。
  • 登录后请立即修改密码,并删除该文件。

部署说明

环境要求

  • Docker 20.10.0+
  • Docker Compose v2.0.0+

数据持久化

建议挂载以下目录以保证数据安全:

目录 用途
./data 数据库、系统配置与自动生成的密钥和初始管理员密码文件
./uploads 本地上传文件

只要 ./data 卷保留,SESSION_SECRET / CONFIG_SECRET 留空时会自动生成并持久化到卷内,重启进程或重建容器都不会导致用户掉线、也不会让已加密的内容无法解密。删除 ./data 会同时丢失数据库和这些密钥。

支持三种数据库:

  1. sqlite (默认)
  2. mysql
  3. postgres

修改数据库在.env内DB_TYPE配置

MySQL / PostgreSQL 的 TLS 由 DB_TLS_MODE 控制:

取值 行为
auto(默认) DB_HOST 解析为本机/私有地址(含 Docker 网络)时按 preferred,公网地址时按 verify-full
disable 不使用 TLS
preferred 服务端支持则使用 TLS,不校验证书;不支持则明文
required 必须使用 TLS,不校验证书
verify-ca 必须使用 TLS,校验 CA(DB_CA_CERT_PATH,留空使用系统 CA),不校验主机名
verify-full 必须使用 TLS,校验 CA 和主机名(DB_TLS_SERVER_NAME,留空等于 DB_HOST)

同一 Docker 网络内的自建数据库(例如 DB_HOST=mysql)无需额外配置;连接云厂商 VPC 内的托管数据库时,如需严格校验请显式设置 DB_TLS_MODE=verify-full。启动日志会输出最终生效的模式。

Telegram 存储配置

使用 Telegram 作为存储后端时,需要获取 Telegram User ID:

向机器人 @userinfobot 发送 /start,即可获取你的 ID。

配置方式

所有配置都可以直接在容器编排里设置,不需要进容器改 /app/.env。

Docker Compose:编辑 docker-compose.yml 的 environment 段,或把 .env.example 复制为 .env(compose 会自动读取并替换 ${VAR}):

cp .env.example .env
vim .env    # 至少改 APP_URL
docker compose up -d

docker run:用 -e 逐个传入,例如:

docker run -d --name oneimg -p 8080:8080 \
  -e APP_URL=https://img.example.com \
  -e DEFAULT_USER=admin \
  -e MAX_FILE_SIZE=20971520 \
  -e TRUSTED_PROXIES=172.17.0.0/16 \
  -v /data/oneimg:/app/data \
  -v /data/oneimg-uploads:/app/uploads \
  git.bytevibe.dev/gary/oneimg:latest

优先级:编排注入的环境变量 > 容器内自动生成的 /app/.env。

应用首次启动时若发现工作目录没有 .env 会自动生成一份模板,但加载时(godotenv)不会覆盖已存在的环境变量,所以容器注入的值始终生效,容器内 .env 只用来补全未注入的默认项。这也意味着容器里那份 .env 可以完全不管。

早期版本会把 .env 文件放在容器内,重建容器即丢失;现在密钥类的自动生成值都落在 ./data 挂载卷里(data/.config_secret、data/.initial_admin_password),持久化与重建都不会变。

常用变量:

变量 默认值 说明
APP_URL http://localhost:8080 公网必改。API 返回的图片 URL 取自该值
GITEA_URL https://git.bytevibe.dev 账户页管理员版本信息使用的 Gitea 地址
GITEA_REPOSITORY gary/oneimg 账户页管理员版本信息使用的仓库路径(所有者/仓库名)
GITEA_TOKEN 空 私有仓库访问令牌,公开仓库留空
SERVER_PORT 8080 容器内监听端口
HOST_BIND_IP / HOST_PORT 127.0.0.1 / 8080 直连模式发布到宿主机的地址与端口
TRAEFIK_ENABLED 空 设为 1 加载 Traefik 覆盖配置;空值使用直连模式
TRAEFIK_HOST img.example.com Traefik Host 路由域名
TRAEFIK_NETWORK frontend Traefik 与 oneImg 共用的外部 Docker 网络
TRAEFIK_ENTRYPOINTS https Traefik 入口点
TRAEFIK_CERTRESOLVER cloudflare Traefik TLS 证书解析器
TRAEFIK_MIDDLEWARES real-ip@file Traefik 中间件列表,需在 Traefik 中预先定义
DB_TYPE sqlite sqlite / mysql / postgres
DB_TLS_MODE auto 数据库 TLS 模式,见上文「数据库」
DEFAULT_USER / DEFAULT_PASS admin / 空 初始管理员;DEFAULT_PASS 留空则随机生成
SESSION_SECRET 空(自动持久化) 会话与 OIDC/CAS state 签名密钥,留空时生成到 data/.session_secret
CONFIG_SECRET 空(自动持久化) 配置与图片加密密钥,留空时生成到 data/.config_secret;显式设置必须 ≥32 字符且不可更换
MAX_FILE_SIZE 10485760 单文件上限(字节),另有 32MB 硬上限
ALLOWED_TYPES jpeg/png/gif/webp 允许的 MIME,逗号分隔
TRUSTED_PROXIES 空 反代信任的 IP/CIDR,留空表示不信任任何代理

完整清单见 .env.example。


反馈与贡献

本仓库是基于 onexru/oneimg 的定制扩展版本。欢迎在 Gitea Issues 提交与本仓库相关的问题或功能建议,也欢迎通过 Pull Request 贡献代码。需要了解上游实现或原始版本时,请访问 上游仓库。