CloudGallery:零成本打造无限容量的 iOS 风私有图床

摘要:受够了第三方图床的限制?担心数据安全?本文介绍如何利用 Python Flask 和 Hugging Face Spaces,零成本搭建一个支持无限存储、私有加密、且拥有 iOS 磨砂质感 UI 的个人图床系统。

1. 背景与痛点

作为一名技术爱好者,在撰写博客或使用 Obsidian/Notion 做笔记时,图床是不可或缺的基础设施。但市面上的解决方案总是不够完美:

  • 第三方图床:存在收费、容量限制或跑路风险。
  • GitHub 仓库:国内访问不稳定,且存在仓库大小限制。
  • 对象存储 (OSS/S3):按流量计费,一旦被恶意刷流量,费用不可控。

服务器搭建才是最优解,但没有服务器怎么办呢?

于是我将目光投向了 Hugging Face (HF)。HF 提供的 Dataset 存储不仅免费、理论容量无限,而且由大厂背书,稳定性极高。基于此,我开发了 CloudGallery —— 一个高颜值、私有化的图床解决方案。


2. 界面设计:追求极致的“果味”

在设计 UI 时,我抛弃了传统的后台管理风格,深度参考了 iOS 的设计语言,采用了大量的 毛玻璃(Glassmorphism) 特效。

2.1 极简登录

登入界面

为了保证私有性,图床自带鉴权系统。登录页采用动态壁纸加磨砂玻璃卡片,清爽无广告。

2.2 沉浸式管理

主界面

主界面支持批量多选上传,后端会自动将文件名处理为短字符(如 a9b2.jpg),避免文件名冗长。

2.3 悬浮预览 (Lightbox)

点击图片后,不再是生硬的页面跳转。我实现了一个悬浮预览层,背景自动进行高斯模糊(Blur)处理,图片悬浮于主页之上。底部配有类似 iPhone 相册的 Filmstrip(胶卷栏),支持丝滑的左右滑动切换。

预览页


3. 核心功能与技术实现

除了 UI,CloudGallery 在功能上也解决了几个核心痛点。

3.1 核心痛点:GitHub 401 问题

这是开发过程中遇到的最大技术挑战。

  • 如果将 HF Dataset 设为 Private(私有),GitHub 无法直接访问图片链接(报错 401 Unauthorized)。
  • 如果设为 Public(公开),则所有人都能看到你的所有图片,隐私无法保障。

3.2 解决方案:反向代理模式 (Proxy Mode)

我在 Flask 后端实现了一个中转接口。当你复制链接时,得到的是我的应用地址;当 GitHub 请求图片时,我的服务器会拿着私有 Token 去 HF 取回数据,再流式转发给 GitHub。

核心代码片段 (main.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests
from flask import Response

@app.route('/file/<path:filename>')
def get_image_file(filename):
# 1. 构造真实的 HF 原始地址
url = f"https://huggingface.co/datasets/{DATASET_NAME}/resolve/main/{filename}"

# 2. 带着服务器端的 Token 进行鉴权请求
headers = {"Authorization": f"Bearer {HF_TOKEN}"}

# 3. 使用 stream=True 进行流式转发,降低内存占用
r = requests.get(url, headers=headers, stream=True)

return Response(r.iter_content(chunk_size=1024),
content_type=r.headers.get('Content-Type'))

3.3 其他特性

  • 无限存储:基于 Hugging Face Datasets。
  • 隐私安全:Dataset 设置为 Private,只有通过你的 App 鉴权后才能上传/删除。
  • 极简文件名:使用 UUID 前4位生成短文件名。
1
2
# 文件名生成逻辑
name = f"{uuid.uuid4().hex[:4]}{ext}"

4. 部署教程:如何拥有同款?

本项目基于 Docker 部署,你可以直接在 Hugging Face Spaces 上免费托管。

准备工作

第一步:创建存储仓库

  1. 登录 Hugging Face,点击 New Dataset
  2. 起个名字(例如 my-images)。
  3. 关键点:Type 选择 Private(私有)。

第二步:获取 Access Token

  1. 进入 Settings -> Access Tokens
  2. 创建一个新 Token,权限必须选择 Write(写入权限)。
  3. 复制这个 Token (hf_xxxx...)。

第三步:创建应用容器 (Space)

  1. 点击 New Space
  2. SDK 选择 Docker
  3. Hardware 选择默认的 Free 即可。

第四步:配置环境变量

在 Space 的 Settings -> Variables and secrets 页面,添加以下变量:

变量名 描述 示例值
HF_TOKEN 刚才复制的 Write Token hf_...
DATASET_NAME 你的数据集名称 username/my-images
ADMIN_USER 自定义登录账号 admin
ADMIN_PASS 自定义登录密码 password123

第五步:上传代码

将项目中的 main.pyDockerfile 上传到 Space 的 Files 中。等待几分钟构建完成后,点击 App 即可开始使用!



⚡ 进阶:国内访问加速 (Cloudflare Worker)

由于 Hugging Face 官方域名 (hf.space) 在国内访问不稳定或被阻断,推荐使用 Cloudflare Worker 进行反向代理。

⚠️ 注意: 为了支持反向代理和自定义域名,请务必使用本项目中的 cf.py 文件

1. 部署代码选择

本项目提供了两个版本的核心代码:

  • main.py (标准版):适合海外环境,逻辑纯净,默认生成官方直链。
  • cf.py (国内加速版)国内用户请用这个! 它增加了 CUSTOM_DOMAIN 支持,修复了反代环境下的登录跳转和链接生成问题。

食用方法:
在将代码上传到 Hugging Face Space 时,请 直接复制 cf.py 的内容覆盖到 main.py(或者修改 Dockerfile 的启动命令为 CMD ["python", "cf.py"])。

2. 创建 Cloudflare Worker

  1. 登录 Cloudflare,进入左侧 Workers & Pages
  2. 点击 Create Application -> Create Worker -> Deploy
  3. 点击 Edit code,清空原有代码,粘贴以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);

// ⚠️ 修改这里:填入你 Space 的真实直连地址 (不要带 https://)
const targetHost = "你的用户名-项目名.hf.space";

url.hostname = targetHost;
url.protocol = "https:";

// 构造请求
const newRequest = new Request(url.toString(), {
method: request.method,
headers: request.headers,
body: request.body,
});

return fetch(newRequest);
},
};
  1. 点击右上角 Deploy 保存。你将获得一个 xxx.workers.dev 的访问地址。
  • (可选推荐):在 Worker 的 Settings -> Triggers 中绑定你自己的自定义域名 (如 img.yourdomain.com),访问更稳定。

3. 配置 Space 适配反代域名

回到 Hugging Face Space 的 Settings -> Variables and secrets,新增一个变量:

类型 变量名 描述 示例值
Variable CUSTOM_DOMAIN 你的 Worker 地址或绑定的自定义域名 (必须带 https,不带结尾斜杠) https://img.yourdomain.com

作用cf.py 读取到此变量后,会自动修正登录跳转路径,并将主页生成的“复制链接”替换为你的加速域名,确保国内可访问。


5. 结语

CloudGallery 是一个典型的“小而美”的项目。它利用了开源社区的免费资源,通过 Python 简单的逻辑胶水,解决了一个实际的生产力痛点。

如果你也受够了商业图床的限制,不妨动手试一试,搭建一个完全属于自己的云端相册。

项目 GitHub 地址:

👉 CloudGallery