前言

现在markdown越来越受欢迎,但是markdown有一个很麻烦而且一直很难解决的问题就是文章中图片资源的处理。


不像word、pdf这种将图片内嵌在文件中,markdown只能引用外部的图片资源,这意味着要么在本地弄一个文件夹专门用来存放图片,通过相对路径引用;要么将图片存放在网上,通过图片链接引用。

如果存放本地以相对路径作为引用的方案,那么传播文档时还要将资源文件进行打包,并且以后想要发表到其他站点,就要考虑如何将这些本地文件转换成网络资源。除非是自用做做笔记,并且是纯本地模式使用,否则这种方案会很麻烦。

所以我个人更倾向于将图片存放在网上引用图片链接的形式,也就是所谓的图床。


但是使用图床也带来了很多的问题。

如果使用免费的图床,以后跑路了怎么办?如果使用GitHub、Gitee这类公共仓库,GitHub的网络稳定性是一个问题,而Gitee后来的审核政策导致图床无法使用也是一个问题。

而使用付费的图床,像是阿里的OSS、腾讯的COS等,万一被刷了,如果没有及时发现,可能一套房就被刷进去了。

图床的易用性也是一个问题,比如使用GitHub当图床,那么就需要在GitHub网页上上传图片,然后点开raw链接,或者在本地提交,然后push到仓库。这在我看来还是稍显麻烦的,不那么优雅。不过还好PC/Mac端有对应的工具,我也没有在移动端写markdown的需求,所以易用性倒是挺容易解决。

所以我思考了一些图床的方案,写下了这篇文章。


当然,我也没有想到一种可以既要又要还要的完美方案,每一种方案都有各自的局限性,只能是根据各种方案的优缺点,以及自身的需求做好取舍,选择一种最适合的方案。

另外,我希望数据是掌握在我自己手中的,所以文中没有列举公共免费图床的方案,这种直接网上一搜就有一大堆,该文章就不赘述了。


好了,废话不多说,接下来我将直接列出各个方案的组合及其优缺点,以供快速参考,不过在这之前先解释一下表格中各个方案的属性表示的含义。

属性解释

成本

就是正常情况下,维持这个图床所需要花的钱。

成本可控

是否会有意外因素,导致成本飙升。比如单OSS方案,可能会被刷流量,导致面临巨额账单。

隐私性

图床中的图片是否全部暴漏在公网中。比如使用GitHub作为图床,图床中的图片几乎是完全暴漏的,不能上传隐私性的图片。

网络稳定性

图片下载的速度。使用国内OSS方案,下载速度比较高,网络稳定性好;而像GitHub图床,由于不可抗力,普通用户无法访问。

是否需要域名

顾名思义,就是是否需要购买一个域名。普通的域名其实很便宜了,需要注意的是购买的时候要注意下续费价格,有些域名可能首年只要几块钱,续费价格很贵。

可迁移性

将一个图床的数据迁移到另一个图床,原来的图片链接是否仍然可访问。

举个例子,我以前使用过Gitee做图床,md文件中直接通过Gitee的域名进行引用,后面政策变更导致无法访问,以前的图片链接全部失效。

如果对可迁移性有要求,那就必须要申请域名,并且做一层路由转发。

举个例子:

原先使用Github作为图床,原图片链接形如:http://raw.github.com/user/repo/b.png

但是实际md中引用的自己的域名:http://img-gh.flycat.tech/user/repo/b.png

使用了反代将 img-gh.flycat.tech转发到 raw.github.com而不是直接访问原链接。

如果以后GitHub政策也变更,那只要将GitHub中的repo整个clone下来,然后上传到oss,再将 img-gh.flycat.tech/user/repo路由到对应的桶就行了,这样原来的图片链接仍然能够访问。

备案要求

是否需要备案。国内备案大概需要1~20天左右,周期会比较长,所以也是一个需要考虑的因素。

方案比较

组合 成本 成本可控性 隐私性 网络稳定性 是否需要域名 可迁移性 备案要求
GitHub 可控 不可迁移
GitHub+域名+Cloudflare 可控 可迁移
GitHub+域名+Cloudflare+VPS 可控 可迁移
OSS 不可控 不可迁移
OSS+域名 不可控 可迁移
OSS+域名+CDN 可控 可迁移
OSS+域名+同机房服务器 可控 可迁移
自建图床 可控 可迁移

搭建教程

一、GitHub

GitHub是代码托管平台,其实很多人也会将文章的图片上传到GitHub中作为图床使用。

除了GitHub之外,像GitLab、GitBucket等也是可以用的,国内的Gitee已经开启防盗链,图床功能已经废了。

另外有个需要注意的是,一般代码托管平台都会有存储大小限制,比如GitHub限制单个仓库最大容量为1G,单个文件不能大于100M,不过我想也不会有人上传100M以上的图片吧。

单个仓库的容量限制,我采取的方案是创建多个仓库。

接下来就开始具体的教程。

创建GitHub账号

个人有些强迫症,所以不想将主仓库和图床的仓库全部放在同一个账号之下,所以我是创建的一个GitHub小号,专门用来存放图床。

另外主账号的用户名有可能变更,到时候就会导致图片链接不可用,所以创建一个小号还是很有必要的。

创建仓库

由于GitHub有单个仓库1G的限制,所以我是预先创建了10个仓库,以img_bed为前缀,用数字做编号,比如img_bed_01、img_bed_02等。仓库必须设置为公开,否则无法访问。

GitHub图床账号示例

上传图片

上传图片可以直接在网页上操作,随便进入一个仓库,然后点上传文件就行了。

但是手动上传的方式很麻烦,而且还不能自动创建目录以及自动命名,可以参考后文中的图床上传工具

CleanShot 2024-03-22 at 14.19.28@2x

获取图片链接

如果没有使用图床上传工具,那么每次手动上传之后,都需要手动获取图片的链接,如果直接引用https://github.com/xxxxxx/img_bed_03/blob/main/202403042257882.png是不可用的,因为只是一个网页,进入这个页面,然后点开raw按钮之后,才是真正的图片链接(注xxxxxx是github用户名)。

不过刚刚看了一下github已经去掉了raw的按钮,不过也可以通过图片右键在新标签页打开然后复制图片地址即可。

复制后的图片链接形式如下:https://raw.githubusercontent.com/xxxxxx/img_bed_03/main/202403042257882.png。

方案总结

这种方案优点是零成本,背靠GitHub,不用担心有被攻击的风险,并且GitHub作为国际性的大平台,也不会受国内的法律约束,未来很长的时间内都是值得信赖的。

但是缺点也有很多,正因不受国内法律约束,GitHub在国内的网络访问体验并不太好,如果只是自用,并且像我一样常驻梯子,那这点缺点几乎可以忽略,但如果有分享的需求,或者平时不会常驻梯子,那网络稳定性的问题就不可忽视了。

另外,GitHub图床必须公开仓库,这也就意味着别人可以随意浏览你的图床里的所有内容,这一点就看个人是否介意以及是否有隐私的需求了。

最后,虽然GitHub是国际性的大平台,但是这世界很多发生的事情都无法预料,以前用Gitee当图床的时候,也认为Gitee是值得信赖的,那么这个时候可迁移性的需求就很重要了。

而GitHub中的域名是固定为raw.githubusercontent.com的,我们不可能去更改此域名的DNS,如果万一哪天GitHub真如Gitee一般加了防盗链,或者加入了审查功能,那旧图片链接就全部失效了。

所以接下来将介绍一种基于GitHub的方案,增加域名解析,实现可迁移图床的能力。

二、GitHub+域名+Cloudflare

前文中提到过GitHub作为图床的几个缺点:网络稳定性问题、不可迁移的问题,那么接下来的这个方案,通过加入自己的域名和套一层Cloudflare,可以解决这个问题。

当然想要达到图床可迁移的效果,必须要有一个长期持有的域名,如果你只买了一年的域名就不用了,那域名到期后原来的图片就全都失效了,还不如直接使用GitHub raw链接。

像我是直接在阿里云花了199一次性买了10年期限的域名,10年之后续费也才几十块钱一年,我想对大部分人来说应该都拿得出来。

另外一个需要解决的问题是网络的问题,如果不使用梯子,在国内访问GitHub的图床是非常缓慢的,甚至有些地区直接无法访问,这个时候就可以套一层Cloudflare,并开启代理功能,虽然访问速度没法跟放在国内图床的速度相比,但是至少能够访问。

接下来将介绍这种方案的流程。(需要注意的是,这里只会介绍大致的流程,对于域名的注册、详细的解析等具体流程可以自己上网找教程)

准备GitHub

该方案是基于GitHub方案优化而来的,所以GitHub图床的准备跟前文所流程一致,唯一不同的是,最终使用的图片链接不是使用的raw.githubusercontent.com,而是我们自己的域名,这点将在后面介绍。

准备一个域名

域名的选择有很多,像国内的阿里云、腾讯云等都有提供域名服务,国外也有一些域名提供商,如NameCheap、NameSilo、Godaddy等,随便选一个就好了。需要注意的是,如果有备案的需求,最好选用国内的服务商,否则需要先将域名转国内才能备案。我的域名是在阿里云购买的,后面也已阿里云为例。

准备Cloudflare

Cloudflare是一家提供内容传递网络、安全性服务、域名注册和其他互联网基础设施解决方案的公司,我们前面申请域名后,不使用域名服务商自己提供的解析服务,而是交由Cloudflare来解析,Cloudflare的DNS提供了代理模式,你可以把它当成一个梯子。

注册Cloudflare账号之后,进入Cloudflare控制台,点击 Add a site添加站点,然后选择免费的方案,添加成功后会进入到这样一个界面:

CleanShot 2024-03-22 at 15.15.40@2x

这个页面是用来配置域名的域名解析服务器,比如我在阿里云购买的域名默认使用的是阿里云提供的域名解析服务器,因为我们需要用到域名的代理功能,所以需要cloudflare托管域名解析。

首先进入阿里云的域名控制台,选择域名,操作中点击管理,进入域名管理界面,找到DNS服务器,可以看到我现在用的DNS服务器地址就是cloudflare的。点击右边的修改DNS,进入到DNS管理界面。

CleanShot 2024-03-22 at 15.25.51

然后将cloudflare的DNS服务器地址填入,点击确定即可。

aria.ns.cloudflare.com
noah.ns.cloudflare.com

CleanShot 2024-03-22 at 15.24.59@2x

回到cloudflare,点击 Check nameserver now按钮,cloudflare就会检测DNS服务器是否修改成功,这个过程可能需要等一会。

激活成功后cloudflare会发一封邮件过来,在此之前可以先做一下配置。

Cloudflare配置

这里使用的是cloudflare的worker功能,这个worker类似于在nginx写lua脚本,可以自定义功能。这里需要实现的是将请求转发到raw.githubusercontent.com这个域名下。

注:试过使用DNS的CNAME解析到raw.githubusercontent.com,但这样host会变成自己的域名,导致GitHub服务器找不到对应的服务。

进入Workers & Pages的Overview页面,这里可以看到我已经建了两个worker,一个是用于github图床的,另一个是之前用于阿里云oss图床的。

页面上红框标记的地方可以看到有个Requests today,这个是worker的使用额度,每天上限10万次,我想对于大部分人来说,这个数量已经绰绰有余了。

CleanShot 2024-03-22 at 15.41.13@2x

点击Create application新建worker,输入worker名称,然后点击 Deploy部署,部署完之后点击右上角的 Edit Code编辑代码,然后将下面的代码输入进入:

/**
 * Welcome to Cloudflare Workers! This is your first worker.
 *
 * - Run "npm run dev" in your terminal to start a development server
 * - Open a browser tab at http://localhost:8787/ to see your worker in action
 * - Run "npm run deploy" to publish your worker
 *
 * Learn more at https://developers.cloudflare.com/workers/
 */

const TELEGRAPH_URL = 'raw.githubusercontent.com';

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url);
  url.host = TELEGRAPH_URL;

  const modifiedRequest = new Request(url.toString(), {
    headers: request.headers,
    method: request.method,
    body: request.body,
    redirect: 'follow'
  });

  const response = await fetch(modifiedRequest);
  const modifiedResponse = new Response(response.body, response);

  // 添加允许跨域访问的响应头
  modifiedResponse.headers.set('Access-Control-Allow-Origin', '*');

  return modifiedResponse;
}

然后点击右上角的 Save and deploy保存代码。

worker创建好之后,选择主页的Websites,然后选择你添加的域名,左边列表有一个 Workers Routes的菜单,点击进入之后,点击 Add route添加路由。

route可以使用一个子域名,用*号匹配所有路径,Worker则选择刚刚创建的,我的配置如下:

CleanShot 2024-03-22 at 15.54.41@2x

这样所有经过img-gh.flycat.tech域名的请求都会交由Worker对请求进行转发,然后修改一下GitHub图床的域名即可。例如:

原图片链接:

https://raw.githubusercontent.com/xxxxxx/img_bed_03/main/202403042257882.png

替换后图片链接:

https://img-gh.flycat.tech/xxxxxx/img_bed_03/main/202403042257882.png

这样就能使用自己的域名访问图片了,如果以后迁移图床就很方便。具体图床迁移教程可以参考后文:如何迁移图床

聊胜于无的隐私优化

前文说到,GitHub图床中的内容是完全公开的,因为链接中带有GitHub用户名,只要通过用户名进入我们的GitHub主页,就能随意浏览图床中的内容了。

这里可以稍微优化一下,在刚刚的worker代码中,只是简单做了一层转发,但既然worker是使用js语言实现的,那就可以在js中自由地定义我们自己的规则。

优化后的代码如下:

/**
 * Welcome to Cloudflare Workers! This is your first worker.
 *
 * - Run "npm run dev" in your terminal to start a development server
 * - Open a browser tab at http://localhost:8787/ to see your worker in action
 * - Run "npm run deploy" to publish your worker
 *
 * Learn more at https://developers.cloudflare.com/workers/
 */

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url);
  const { pathname } = url;

  // 提取请求路径中的映射数字
  const matches = pathname.match(/^\/(\d+)\/(.*)/);
  if (!matches) {
    return new Response('Invalid URL', { status: 400 });
  }
  const mappingNumber = matches[1];
  const newPathname = `/xxxxxx/img_bed_${mappingNumber}/${matches[2]}`;

  // 构建新的 URL
  const newUrl = new URL(`https://raw.githubusercontent.com${newPathname}`);
  
  // 发起修改后的请求
  const modifiedRequest = new Request(newUrl.toString(), {
    headers: request.headers,
    method: request.method,
    body: request.body,
    redirect: 'follow'
  });

  // 发起修改后的请求并返回响应
  const response = await fetch(modifiedRequest);
  const modifiedResponse = new Response(response.body, response);

  // 添加允许跨域访问的响应头
  modifiedResponse.headers.set('Access-Control-Allow-Origin', '*');

  return modifiedResponse;
}

稍微解释一下代码功能,pathname.match(/^\/(\d+)\/(.*)/)用于解析原请求路径中跟路径下的数字,提取之后将数字拼接在 /xxxxxx/img_bed_${mappingNumber},然后再将剩下的路径拼接在后面。其中xxxxxx是GitHub用户名,配置在cloudflare中,无法通过原图片链接获取用户名。

优化之后新旧图片链接对比如下:

原图片链接:

https://raw.githubusercontent.com/xxxxxx/img_bed_03/main/202403042257882.png

替换后图片链接:

https://img-gh.flycat.tech/03/main/202403042257882.png

其实就是把中间的 xxxxxx/img_bed_省略掉了。

这样虽然仓库仍然是公开的,但至少拿到图片链接的人无法找到你的仓库。

当然,对我来说更重要的是我认为第二种的链接更优雅

方案总结

这个方案解决了国内访问的问题和图床无法迁移的问题,并在一定程度上保护了图床的隐私。

当然,在国内访问的网络问题仍然不太稳定,在部分高峰时段,还是会有图片响应缓慢的问题。

另外cloudflare的worker有每天10万次请求的限制,如果访问量很大的话,那这个方案就没那么合适了。

三、GitHub+域名+Cloudflare+VPS

这个方案跟第二种差不太多,只不过把Worker的工作交给了nginx,如果手头刚好有一个海外的VPS,那么还是不错的,海外VPS的带宽一般都比较高,我本地开梯子通过ip从服务器下载文件,可以跑满7MB/s,比阿里的3Mbps小水管高太多太多了。

不过海外的VPS一般都比较贵,以我使用的亚马逊Lightsail来说,2C1G的服务器每月5刀,合计36左右,而我的阿里云ECS搞活动2C2G一年才99。

另外该方案会使用VPS的流量,Lightsail 5刀服务器提供2T流量,3.5刀提供1T流量,如果访问量很大的话这些流量仍然不够。

不过如果有这么大的访问量的需求,应该也不会看我这篇文章了吧。

如果手头没有海外VPS就不太推荐这个方案,专门用来做图床成本太高。

准备GitHub

准备GitHub的流程跟前面两种方案的一致。

准备VPS

这个方案需要有一台海外的VPS,如果用国内的,我试过,几乎无法访问。

VPS安装好nginx,或其他反代应用,然后增加反代配置,我的配置如下:

server {
        listen       443;
        server_name  img-gh.flycat.tech;

        ssl_certificate         cert/live/flycat.tech/fullchain.pem;
        ssl_certificate_key     cert/live/flycat.tech/privkey.pem;

        location / {
                rewrite ^/(.*)$ /xxxxxx/img_bed_$1 break;
                proxy_pass      https://raw.githubusercontent.com;
                proxy_set_header Host raw.githubusercontent.com;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

}

将其中的xxxxxx替换成你用来做图床的github用户名即可。

准备域名和Cloudflare

可以参考方案二的流程:准备Cloudflare

配置Cloudflare

注册好域名并添加到Cloudflare之后,进入对应的域名配置,点击左侧列表的DNS-Records,点击 Add record添加一条解析记录:

CleanShot 2024-03-22 at 17.03.20@2x

type选择A,Name是你的子域名,然后在IPv4填你的ip地址。

如果你是海外VPS,后面的Proxy status最好选上,这个Proxy status是Cloudflare提供的代理,相当于一个梯子,即使你的VPS被墙了也可以在境内访问,而且还能隐藏VPS的ip地址。

如果是国内的VPS就不要选了,那就变成减速器了。

点击保存按钮,如果是新添加的,应该马上就能生效了。

至此,该方案就配置完毕,图片转换规则如下:

原图片链接:

https://raw.githubusercontent.com/xxxxxx/img_bed_03/main/202403042257882.png

替换后图片链接:

https://img-gh.flycat.tech/xxxxxx/img_bed_03/main/202403042257882.png

方案总结

总的来说,这个方案不是很推荐,既需要域名还需要海外VPS。

不过我刚好手头有台亚马逊的Lightsail,实测了一下比使用Cloudflare worker要稍微稳定一点,使用worker时没天都会有几分钟不可用,可以作为第二种方案的替代方案。

四、OSS

国内很多云厂商都有提供OSS(Object Storage Service)对象存储服务,比如阿里云的OSS、腾讯云的COS、七牛云、又拍云、亚马逊的S3等等,访问速度快,隐私性高,企业中的图片很多也是存储在OSS中的。

阿里云OSS的计费规则比较复杂,费用包括存储费用、流量费用、请求费用等等,流量费用又分公网流出流量,配置了CND还有CDN流出流量等等,非常复杂。

据说七牛云计费更简单,而且还有免费额度,不过我没用过,可以作为备选。

不过个人正常使用的情况下,这些费用还是很低的,这些计费规则倒也不用太过在意。

比较让人不放心的是,如果有人拿OSS图片链接来刷流量的话,那可能会收到一大笔费用的账单,这些厂商没有提供欠费停止服务的功能,所有被恶意刷流量导致的费用都需要自己承担。之前在网上看到过一个老哥被刷了20多T流量,估计得几千上万了吧。所以说这个方案的成本不可控。

创建OSS桶

这里以阿里云OSS为例,其他对象存储大差不差。

首先登录/注册阿里云,进入对象存储控制台,然后点击创建OSS桶。

CleanShot 2024-03-22 at 17.32.35@2x

地域根据需求选择就好,读写权限需要选择公共读(就是这个导致被刷流量的风险),名字自己取就好,然后点击完成创建。

创建完桶之后,进入Bucket列表,选择刚刚创建的桶,就能在文件列表上传图片了。

点开上传的文件可以看到图片的访问URL。

其他配置

为了防止被别人盗用图片,可以设置一下防盗链功能,将自己的网站域名加入白名单(如果有的话)。

当然,防盗链并不能防止被刷流量。

方案总结

此方案使用大厂的对象存储,网络访问快,稳定性好,正常使用的话每个月只需要维持很低的成本即可,但是最大的问题是会有面临巨额账单的风险,需要谨慎使用。

另外,由于使用的是oss提供的域名,将来想要迁移图床也是基本不可能的,除非把现有文章的链接全部替换为新图床的链接,如果只是在本地文件中还好,使用编辑器批量替换即可。如果是在很多地方都使用了这个图床,那迁移将是一个浩大的工程。

五、OSS+域名

在方案四的基础上,加上自定义域名就能实现图床可迁移了。

但是如果使用的是国内的对象存储,则必须是已备案的域名才能使用。

根据各个地区的具体情况,备案的时间也各不相同,我的备案花了半个月。

配置域名

该方案是基于方案四的,配置好OSS桶以及域名备案成功之后,进入OSS控制台 > OSS桶。

进入Bucket配置>域名管理,点击绑定域名,然后输入已备案的域名即可。

如果你的域名是阿里云购买的,并且使用了阿里云的域名服务器进行解析,可以选择自动添加 CNAME 记录,然后点击确认绑定即可。

CleanShot 2024-03-22 at 17.50.56@2x

如果是像我一样使用的cloudflare做域名解析,那么就需要去cloudflare控制台手动添加cname记录。

进入DNS配置页面,如图:

CleanShot 2024-03-22 at 17.57.07@2x

假设OSS域名是bucket-name.oss-cn-guangzhou.aliyuncs.com,自定义域名是img-oss.flycat.tech。

TYPE选择CNAME,Name是输入img-oss,Target就是OSS域名bucket-name.oss-cn-guangzhou.aliyuncs.com,后面的Proxy status一定要取消选择,不然就变成减速器了。

填好后点击Save保存即可,回到刚刚的OSS域名列表,点击域名绑定配置,正常的话可以看到显示为已配置。

证书配置

如果想要通过https访问,则需要配置证书,证书配置参考:阿里云免费申请SSL证书

不过现在阿里云的免费证书有效期只有3个月,3个月之后需要手动申请新的证书,还是挺麻烦的,看网上阿里云有提供相关API,有时间可以写个定时脚本定期检测并申请证书。

申请好之后在Bucket配置的域名管理中,在对应域名后面点击证书托管,然后选择刚刚申请好的证书即可。

获取图片链接

图片链接只需要将原本的OSS域名替换为自定义域名即可,比如:

原OSS图片链接:

https://bucket-name.oss-cn-guangzhou.aliyuncs.com/24/03/22/image.jpg

替换后图片链接:

https://img-oss.flycat.tech/24/03/22/image.jpg

方案总结

这个方案只是在方案四的基础上增加了自定义域名,方便未来的图床迁移。

六、OSS+域名+CDN

该方案是基于方案五进行了优化。既然都已经备案域名了,那其实不如直接套一层CDN,毕竟CDN的费用要低很多,而且CDN可以配置宽带上限,可以一定程度上缓解被恶意刷流量。不过这个上限的检测有10分钟延迟,最多可能会背负10分钟流量被刷的风险。

OSS和域名的配置参考方案四即可,不过OSS的读写权限需要变更一下。

配置OSS读写权限

方案四中创建OSS桶配置的读写权限是公共读,因为需要接入CDN,为了避免被人绕开CDN直接调用OSS,我们需要将读写权限修改为私有。

CleanShot 2024-03-22 at 18.28.42@2x

这样,别人就无法直接通过OSS访问数据了。

配置CDN

进入CDN控制台,添加域名。

业务信息根据需要选择就好,不过需要注意的是,如果加速全球的话,国外的CDN费用比国内的CDN贵一点。

主要是配置源站信息,点击新增源站信息按钮,源站信息选择OSS域名,下拉框中选择之前创建的OSS桶,然后点击确定即可。

CleanShot 2024-03-22 at 18.33.12@2x

因为我们之前将OSS读写权限改成了私有,所以这里需要授权CDN访问OSS,按照步骤操作即可。

配置证书

同样,想要通过https访问需要配置证书,进入cdn控制台选择对应域名管理,选择HTTPS配置,按说明添加证书即可。

不过CDN的https请求是单独计费的,前500万次请求免费,个人使用应该也够用了。

CleanShot 2024-03-22 at 18.37.55@2x

流量限制

个人使用还是很难担负起巨额账单的,如果怕被刷的话可以增加流量限制。

我是自用图床,网站预计的访问量也不高,所以我配置的是在一分钟内平均带宽超过32Mbps就视为异常流量,CDN就会自动下线,保护我的钱包。

CleanShot 2024-03-22 at 18.44.07@2x

方案总结

此方案我认为是一个不错的选择,成本不高,而且网络稳定,因为是自用域名,今后也方便迁移图床。

不足之处是需要备案域名,以及被刷流量可能还是要损失点钱。

如果想完全避免被刷钱,可以参考下面的方案。

七、OSS+域名+同机房服务器

阿里云的OSS,如果是内网访问是不需要支付流量费用的,但是需要有一台同机房的服务器。

比如我创建的是广州地区的阿里云OSS,那么就需要一台广州地区的阿里云服务器。

实现是通过nginx反代,经由服务器内网访问OSS,那么这样完全不需要流量费用了。

如果手中刚好有一台同机房的服务器,且访问量不大,那么这种方案也是很不错的。

配置读写权限和白名单

OSS读写权限配置为私有,防止被刷。

CleanShot 2024-03-22 at 18.28.42@2x

OSS设置了私有,那服务器如果访问OSS呢?OSS提供了白名单的功能,支持指定ip开放访问。

CleanShot 2024-03-22 at 19.23.23@2x

在OSS桶配置页面,进入Bucket授权策略-新增授权,条件选择ip,然后填入服务器的内网ip即可(公网ip无效)。

配置nginx反代

nginx配置如下:

server {
        listen       443;
        server_name  img.flycat.tech;

        ssl_certificate         cert/live/flycat.tech/fullchain.pem;
        ssl_certificate_key     cert/live/flycat.tech/privkey.pem;

        location / {
                proxy_pass      https://bucket-name.oss-cn-guangzhou.aliyuncs.com;
                proxy_set_header Host $proxy_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        }

}

proxy_pass替换成对应的OSS桶,然后重新加载nginx即可。

方案总结

如果刚好使用的阿里云服务器,并且有备案的域名,那么这个方案是非常合适的,只需要支付少量存储费用即可,每个月可能也就几毛钱。

不过因为是使用nginx反代,带宽会受到服务器的带宽限制,访问量多一点可能会影响web应用的访问速度。

八、自建图床

如果手边有一台服务器,并且不想支付其他费用的话,自建图床也是不错的选择。有一些开源方案可以使用。

  • Lychee,一个开源免费的基于 PHP 的图片管理系统,支持 Docker 部署,可以直接当做图床来用,Lychee 还支持很多扩展。
  • EasyImages2.0,一款功能强大无数据库的图床 2.0版

图床上传工具

以上所有的方案,当需要上传一张图片时都很麻烦,需要先手动上传、文件命名、复制链接,这个时候就需要一个工具,帮助我们自动将图片上传到图床中,并且自动命名,上传后自动生成图片链接。

下面介绍几种常用的工具:

PicGo

PicGo是一个非常受欢迎的图片上传工具,支持阿里OSS、腾讯COS、又拍云、七牛云、GitHub、SM.MS等,并且可以添加插件,比如自定义文件命名规则等。

常用的markdown编辑工具,比如Typora、Obsidian等都支持PicGo,直接将剪贴板的图片粘贴到编辑器就能自动上传。

下图就是我的PicGo配置,我使用的阿里云OSS,并配置了自定义域名,当图片上传成功之后,会自动将图片链接的域名替换为我的自定义域名。

CleanShot 2024-03-22 at 19.42.56@2x

uPic

uPic(upload Picture) 是一款 Mac 端的图床(文件)上传客户端,支持smms、 又拍云 USS、七牛云 KODO、 阿里云 OSS、 腾讯云 COS、 百度云 BOS、微博、Github、 Gitee、 Amazon S3、Imgur、自定义上传接口。

uPic的剪贴板上传体验比PicGo好一点,PicGo反应不怎么灵敏,但是uPic后面的版本需要付费,旧版本中没有阿里云OSS广州区域的选项,所以我现在用的是PicGo。

iPic

iPic是MacOS端独占的图床上传工具,支持上面的常用图床和功能。Typora也内置了iPic的支持。

不过这款是付费的,58一年还是有点贵的,对于我来说免费的PicGo已经够用了。

如何迁移图床

前文中不止一次地提到过迁移图床,那么我是如何实现图床迁移的呢?

以基于GitHub+域名+Cloudflare方案迁移到OSS+域名+CDN的方案为例:

假设基于前者的图床的某个图片的链接是

https://img-gh.flycat.tech/flycat/img_bed_03/main/202403042257882.png

我需要保证,当将GitHub中的图片全部迁移到OSS后,这个图片仍然可以访问。

步骤如下:

  1. 将GitHub图片打包下载;
  2. 在OSS桶的根目录下添加以GitHub用户名命名的目录,比如上述链接的用户名是flycat;
  3. 本地将压缩包解压后,将整个仓库(img_bed_03)目录上传至OSS的flycat目录下;
  4. 将OSS添加img-gh.flycat.tech域名配置,并将img-gh.flycat.tech解析到OSS。

至此图床迁移完毕,迁移到OSS后原来的图片链接仍然能够访问。

那如果是OSS+域名+CDN方案迁移到GitHub+域名+Cloudflare方案呢,比如前者原来的图片链接如下:

https://img.flycat.tech/24/03/22/img01.jpg

而我要放在GitHub中flycat用户的img_bed_04中,将OSS数据迁到GitHub之后,链接的形式是:

https://raw.githubusercontent.com/flycat/img_bed_04/24/03/22/img01.jpg

那这种情况下就需要使用cloudflare的worker功能,在路径前面拼接一个 flycat/img_bed_04前缀,其他情况的处理方法类似,比如包含服务器方案的可以通过nginx配置匹配转发等。

如何缩减存储成本

还有一个问题是,如果使用的OSS付费方案,那么存储空间是需要长期付费的,而我们平时上传的图片,有可能很小,也有能很大。

屏幕分辨率比较高的电脑,截一张图可能就要好几M,当图片数量变多的时候,存储空间还是不容小觑的。

这个时候就可以借助上传工具的图片压缩功能。

uPic工具自带压缩功能,可以选择压缩比例,PicGo则可以下载相应的插件,我使用的插件是picgo-plugin-compress,可以选择压缩为webp格式,在很少损失画质的情况下,大大减少图片大小。

比如我的一个桌面壁纸图片,原图大小10.7MB,压缩为webp之后仅386KB,肉眼看几乎没看出区别。

CleanShot 2024-03-22 at 20.16.02@2x

图床管理

如果是使用的免费图床,图床的管理是无所谓的,也不用在意存储的大小。但如果是用的对象存储这些付费图床,那占用的空间是需要一直付费的,这个时候就希望能有个管理图床的工具,如果所需的图片是以前上传过的,可以直接复用,而不用重新上传占用额外空间。

但是寻找了很久并没有发现这样的工具,毕竟各家服务提供商的api不同,而且也不算是刚需,可能没有人愿意去开发吧。

而且如果是使用PicGo、uPic等这些图床上传工具,也有内置简易的相册管理,对于短期的重复图片也算是够用了。

如果有更好的方案,欢迎在评论区讨论。

个人想法

上面的各种图床方案都有各自的优缺点,没有哪一种是完美的。

其实我们选择图床并不是找相伴一生的另一半,在满足可迁移性的前提下,在不同的场景下可以将数据迁移到其他地方,切换到不同的方案。

比如如果是想自用,或者建站初期访问量小,那么这个时候对网络的要求不高,但是需要低成本,这个时候可以选择GitHub+域名+Cloudflare的方案,只需要付出一点域名的成本,可能也就两倍奶茶钱。

一旦后期访问量上去了,这个时候也可以将数据全部迁移过去,而我的口袋比较薄,不想收到巨额账单,所以必须成本可控,那这个时候就可以选择OSS+CDN的方案。

当然这只是我的思路,实际根据自己的需求来选择就好了。