用GitHub + jsDelivr+自己域名做图床(无限容量流量,免费)

先说一下。。本来是手写的 感觉乱乱的,我让 ai 帮我重新排版了一下, img.gao.gs 是我刚才搭建测试的,完全可以用。

下面是具体步骤:

  • 存储在 GitHub 仓库
  • 走 jsDelivr CDN 流量
  • 用 Cloudflare Workers 做上传接口 + 图床页面
  • 全程使用你自己的域名:img.gao.gs

实现效果:

对个人站 / 论坛 / 博客来说,这套方案可以视为:几乎无限的免费图床


一、整体思路

整套架构大概是这样:

  1. 图片文件存放在 GitHub 仓库(比如:4iz1j1/img-host
  2. jsDelivr 负责从 GitHub 拉文件并做全球 CDN 加速
  3. Cloudflare Worker 提供两个功能:
    • 一个简易 Web 图床页面(上传按钮)
    • 一个上传接口,把文件写入 GitHub 仓库
    • 一个图片阅读接口 /i/*,对外暴露你的域名,然后在内部代理到 jsDelivr
  4. 你的域名 img.gao.gs 指向 Cloudflare Worker

这样就实现:

自己域名 + GitHub 存储 + jsDelivr 流量 + Cloudflare 边缘计算。


二、准备工作

你需要:

  • 一个 GitHub 账号(例:4iz1j1
  • 一个域名,并托管在 Cloudflare(这里用 gao.gs 示例)
  • 将子域名 img.gao.gs 用来做图床入口
  • 已经开通 Cloudflare Workers(免费版就够)

三、Step 1:创建 GitHub 图床仓库

  1. 打开 GitHub,点击右上角 New repository
  2. 填写信息:
    • Owner:你的账号,比如 4iz1j1
    • Repository name:建议 img-host
    • VisibilityPublic
  3. 其他选项都可以关掉(不创建 README、.gitignore、License),点 Create repository

这样就有了一个公开仓库,用来存你所有上传的图片文件。


四、Step 2:创建 Fine-grained Token(只给这个仓库写权限)

为了让 Worker 能把文件写进这个仓库,需要一个 GitHub Fine-grained Personal Access Token

  1. 打开:
    https://github.com/settings/tokens?type=beta
    标题应该是:Fine-grained personal access tokens
  2. 点击右上角绿色按钮:Generate new token
  3. 基本信息:
    • Token name:随便,如 img-upload
    • Expiration:推荐 No expiration
    • Resource owner:选你的账号(例:4iz1j1
  4. Repository access
    • 选:Only select repositories
    • 在下面的列表中选择你刚刚建的仓库:img-host
  5. Repository permissions
    • 切换到 Repository 这一栏
    • 点击 Add permissions
    • 找到 Contents
    • 把 Access 从 Read-only 改成 Read and write
  6. 滑到页面底部,点 Generate token
    GitHub 会显示一串类似:
    github_pat_********************************
    
    Text

    这串 Token 只显示一次,一定要复制保存,后面要用到。

注意:这个 Token 只对你选的那个仓库(img-host)有内容读写权限,相对安全。
真正部署时我们会把它放到 Cloudflare Worker 的 密钥(Secret) 中,前端看不到。


五、Step 3:在 Cloudflare 创建 Worker

  1. 登录 Cloudflare 后台,进入左侧 Workers & Pages(Workers 和 Pages)
  2. 点击 Create application / 创建应用程序
  3. 选择 「从 Hello World! 开始」 新建 Worker。
  4. 起个名字,例如:img-host-worker
  5. 创建好后,会进入一个在线代码编辑器,默认有示例代码。

六、Step 4:替换 Worker 代码

在编辑器里:

  1. Ctrl + A 全选,删除原有代码。
  2. 粘贴下面这份完整代码:
const HTML = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>我的图床 - GitHub + jsDelivr</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:#f5f5f5;margin:0;padding:40px 10px;text-align:center}
.box{background:#fff;max-width:480px;margin:0 auto;padding:24px 18px;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,.08);}
h1{font-size:20px;margin:0 0 10px}
p{margin:6px 0;color:#666;font-size:14px}
input[type=file]{margin:15px 0}
button{padding:8px 18px;border:none;border-radius:6px;background:#3b82f6;color:#fff;font-weight:600;cursor:pointer}
button:disabled{opacity:.6;cursor:not-allowed}
.result{margin-top:16px;font-size:13px;word-break:break-all;text-align:left}
input.link{width:100%;padding:6px 8px;font-size:13px}
img.preview{max-width:100%;margin-top:10px;border-radius:6px}
</style>
</head>
<body>
<div class="box">
  <h1>🖼 我的图床</h1>
  <p>图片会上传到 GitHub 仓库,并通过 jsDelivr 加速</p>
  <form id="form">
    <input type="file" name="file" id="file" accept="image/*"><br>
    <button type="submit" id="btn">上传</button>
  </form>
  <div id="result" class="result"></div>
</div>
<script>
const form = document.getElementById('form');
const btn = document.getElementById('btn');
const resultEl = document.getElementById('result');

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  const fileInput = document.getElementById('file');
  if (!fileInput.files[0]) { alert('请选择图片'); return; }
  const formData = new FormData();
  formData.append('file', fileInput.files[0]);
  btn.disabled = true;
  btn.textContent = '上传中...';
  resultEl.textContent = '';
  try {
    const res = await fetch('/upload', { method:'POST', body: formData });
    const data = await res.json();
    if (!res.ok) throw new Error(data.error || '上传失败');
    resultEl.innerHTML = 
      '外链:<br><input class="link" value="' + data.cdnUrl + '" onclick="this.select()"><br>' +
      '<img class="preview" src="' + data.cdnUrl + '">';
  } catch (err) {
    resultEl.textContent = '错误:' + err.message;
  } finally {
    btn.disabled = false;
    btn.textContent = '上传';
  }
});
</script>
</body>
</html>`;

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const { pathname } = url;

    // 首页:上传页面
    if (request.method === 'GET' && pathname === '/') {
      return new Response(HTML, {
        headers: { 'content-type': 'text/html; charset=utf-8' }
      });
    }

    // 上传接口
    if (request.method === 'POST' && pathname === '/upload') {
      try {
        const formData = await request.formData();
        const file = formData.get('file');
        if (!file || typeof file === 'string') {
          return json({ error: '没有收到文件' }, 400);
        }

        const arrayBuffer = await file.arrayBuffer();
        const base64 = arrayBufferToBase64(arrayBuffer);

        const now = new Date();
        const y = now.getFullYear();
        const m = String(now.getMonth() + 1).padStart(2, '0');
        const d = String(now.getDate()).padStart(2, '0');
        const safeName = file.name.replace(/[^a-zA-Z0-9\\.\\-_]/g, '_');
        const path = `${y}/${m}/${d}/${Date.now()}-${safeName}`;

        const repoUser = env.GITHUB_USER;
        const repoName = env.GITHUB_REPO;
        const branch = env.GITHUB_BRANCH || 'main';

        const apiUrl = `https://api.github.com/repos/${repoUser}/${repoName}/contents/${encodeURIComponent(path)}`;

        const ghRes = await fetch(apiUrl, {
          method: 'PUT',
          headers: {
            'Authorization': `Bearer ${env.GITHUB_TOKEN}`,
            'Content-Type': 'application/json',
            'Accept': 'application/vnd.github+json',
            'User-Agent': 'img-host-worker/1.0'
          },
          body: JSON.stringify({
            message: 'upload image',
            content: base64,
            branch
          })
        });

        if (!ghRes.ok) {
          const text = await ghRes.text();
          return json({ error: 'GitHub API 错误: ' + text }, 500);
        }

        // 对外给你的链接:用自己的域名 + /i/ 路由
        const publicUrl = `https://img.gao.gs/i/${path}`;
        return json({ cdnUrl: publicUrl });
      } catch (e) {
        return json({ error: e.message || String(e) }, 500);
      }
    }

    // 图片外链:/i/ 开头,用你的域名,内部代理到 jsDelivr
    if (request.method === 'GET' && pathname.startsWith('/i/')) {
      const filePath = pathname.slice(3); // 去掉 "/i/"
      const repoUser = env.GITHUB_USER;
      const repoName = env.GITHUB_REPO;
      const branch = env.GITHUB_BRANCH || 'main';

      const cdn = `https://cdn.jsdelivr.net/gh/${repoUser}/${repoName}@${branch}/${filePath}`;

      // 反向代理 jsDelivr 内容,保持地址栏还是 img.gao.gs
      const originRes = await fetch(cdn, {
        headers: {
          'User-Agent': 'img-host-worker/1.0'
        }
      });

      if (!originRes.ok) {
        return new Response('图片拉取失败', { status: 502 });
      }

      const newHeaders = new Headers(originRes.headers);
      // 强制缓存
      newHeaders.set('Cache-Control', 'public, max-age=31536000, immutable');

      return new Response(originRes.body, {
        status: originRes.status,
        headers: newHeaders
      });
    }

    return new Response('Not found', { status: 404 });
  }
};

function arrayBufferToBase64(buffer) {
  let binary = '';
  const bytes = new Uint8Array(buffer);
  const len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return btoa(binary);
}

function json(obj, status = 200) {
  return new Response(JSON.stringify(obj), {
    status,
    headers: { 'content-type': 'application/json; charset=utf-8' }
  });
}
Js

如果你不是用 img.gao.gs,把代码里
const publicUrl = \https://img.gao.gs/i/\${path}\`;` 改成自己的域名即可。

  1. 粘贴完之后,点击右上角 Deploy / 部署

七、Step 5:配置 Worker 环境变量和密钥

在这个 Worker 的页面里:

  1. 点击上方的 Settings / 设置
  2. 找到 Variables / 变量一块。

添加环境变量(普通 – 文本)

添加三条 文本 类型变量:

  • GITHUB_USER = 你的 GitHub 用户名(示例:4iz1j1
  • GITHUB_REPO = img-host
  • GITHUB_BRANCH = main

添加密钥(Secret)

再添加一条 密钥(Secret)

  • GITHUB_TOKEN = 刚才 GitHub 生成的 Fine-grained Token

保存即可。


八、Step 6:测试 Worker(使用默认域名)

Worker 部署好后,Cloudflare 会给你一个类似这样的地址:

https://img-host-worker.你的账号名.workers.dev/
Text

浏览器打开这个地址,你应该能看到一个简单的上传页面:

  • 选择图片 → 点击 “上传”
  • 成功后,会在下方显示一条外链,如:
    https://img.gao.gs/i/2025/11/20/xxxxxxxx.png
    
    Text

并显示图片预览。

此时说明整套 GitHub + Token + Worker 逻辑已经 OK。


九、Step 7:绑定自己的域名 img.gao.gs

1)DNS 新增 CNAME

  1. 在 Cloudflare 后台选择你的主域名 gao.gs
  2. 打开 DNS 管理。
  3. 添加一条记录:
    • 类型:CNAME
    • 名称:img
    • 目标:可以写 workers.devgao.gs 等任意值(因为最终会被 Worker 路由接管)
    • 代理状态:Proxied / 已代理(橙色小云)

2)Workers 路由

  1. 在 gao.gs 这个域名页面,左侧找到 Workers 路由
  2. 添加一条路由(Route):
    • 路由:img.gao.gs/*
    • Worker:选择你的 img-host-worker

保存。

现在访问:

https://img.gao.gs/
Text

看到的就是同一个上传页面,但入口换成了你的域名。

【版权声明】:服务器导航网所有内容均来自网络和部分原创,若无意侵犯到您的权利,请及时与联系 QQ 2232175042,将在48小时内删除相关内容!!

给TA服务器
共{{data.count}}人
人已服务器
技术教程

新北京烤鸭配方 / 材料简单易上手学得快!鸭饼制作 / 鸭酱制作

2025-11-21 7:13:16

技术教程

35个DeepSeek写小说指令合集创意写作必备

2025-11-23 8:05:33

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索