这两天上网冲浪的时候,发现了一个叫作「WebP Server Go」的开源项目。

这个项目是这么介绍的:

Go version of WebP Server. A tool that will serve your JPG/PNG/BMP/SVGs as WebP/AVIF format with compression, on-the-fly.

WebP Server 的 Go 版本,旨在将您的 JPG/PNG/BMP/SVG 图片进行动态压缩并转换为 WebP/AVIF 格式。

简单地说,这是一个自动压缩图片为 WebP/AVIF 格式的工具。

关于 WebP 这一格式,早在《Mikusa Yearly Issue 1》一文中我就有详细地解释过。当时为了节省 CDN 流量的开销,拜托 Z酱帮我写了判断用来自动调用同路径下的 WebP 图片,唯一的不足就是要手动压缩图片并上传到服务器。后来 VOID 更新,我便放弃了这个需要更改主题代码的方案,改为直接使用 WebP 格式的图片。缺点也很明显,我还是需要手动压缩原始图片,再上传 WebP 格式的图片到图床,本地需要保留两份图片文件。至于本地备份的图片,肯定也是 png 或其他格式的原图优先级更高,毕竟 webp 有用到的话我可以手动再压缩。

即使写东西顺带压缩下图片花不了多少功夫,也还是会有一转眼就忘记压缩直接上传原图的时候。不管不顾还好,强迫症发作的时候就会想着删掉原图重新上传。这看起来是个不痛不痒的问题,但也有会感到烦躁的时候。

因此,在发现了「WebP Server Go」之后,我便急忙部署在服务器上运行起来,测试实际的使用效果。

安装

项目提供了 Docker 容器,使用 docker compose 就可以一键安装:

version: "3.9"
services:
  
  webpgo:
    image: webpsh/webp-server-go
    environment:
      - MALLOC_ARENA_MAX=1
    volumes:
      - ./pic:/opt/pics #本地图片路径
      - ./webpgo/exhaust:/opt/exhaust #压缩后的图片缓存
      - ./webpgo/metadata:/opt/metadata #压缩前后的图片元数据缓存
    ports:
      - 3333:3333
    restart: unless-stopped
    container_name: webpgo

volumes 挂载目录中,./pic 指的是本地存放图片的路径,需要挂载到容器中的 /opt/pics 文件夹中。假设你有张图片路径为 ./pic/myblog/test.png ,那么 WebP Server Go 压缩后的链接就是 http://example.com/myblog/test.png

/opt/pics/opt/exhaust/opt/metadata 是配置文件 config.json 中的默认配置,并非不可修改。参考官方 Docker 部署文档1中的说明,我们可以自定义这一配置文件,再挂载到容器中去,以对容器进行一些微调。

原始的 config.json 内容如下(如有更新,请参考官方文档):

{
  "HOST": "0.0.0.0",
  "PORT": "3333",
  "QUALITY": "90",
  "IMG_PATH": "./pics",
  "EXHAUST_PATH": "./exhaust",
  "IMG_MAP": {},
  "ALLOWED_TYPES": ["jpg", "png", "jpeg", "bmp", "gif", "svg", "heic", "nef", "webp"],
  "ENABLE_AVIF": false,
  "ENABLE_EXTRA_PARAMS": false,
  "READ_BUFFER_SIZE": 4096,
  "CONCURRENCY": 262144,
  "DISABLE_KEEPALIVE": false
}

通俗易懂:

  • QUALITY:压缩质量,默认 80,即 80%,有需要可以修改为 90%。
  • IMG_PATH:图片路径,即映射中的 /opt/pics,你也可以修改为 ./pic,只是修改完后不要忘了同时修改 docker-compose.yml 文件。这一配置项亦支持远程路径,即你可以填写 http://example.com 直接从远程链接里抓图,这样就不用本地挂载图片了。
  • IMG_MAP:多路径。按照官方的解释2和示例,这个配置的格式是这么写的:

      "IMG_MAP": {
        "/anon": "/pics1",
        "/soyo": "/pics2",
        "/mygo": "http://example.com"
      },

    简单地说,: 左边填你想要展示的路径,随便什么都行只要格式是 /xxx;右边填具体路径 ./pics1 或远程链接 http://example.com ,多路径就生效了。只不过要注意的是,链接的格式必须为 http?s://.*,即 https://http:// ,不匹配此格式的会被忽略。

  • ALLOWED_TYPES:允许的图片格式。我在测试的时候发现,如果已经是 WebP 格式,程序就会报错。本想向官方提 Issue,但试着在格式中添加了 webp ,程序就不报错了,会直接使用已存在的 WebP 格式图片。(官方已默认添加 webp 格式的图片)

其他部分都没有改动的必要,如果你有需求可以详细参考官方文档自行修改。

修改后的 config.json 保存到本地:

{
  "HOST": "0.0.0.0",
  "PORT": "3333",
  "QUALITY": "90",
  "IMG_PATH": "/pic",
  "EXHAUST_PATH": "./exhaust",
  "IMG_MAP": {
    "/anon": "/pics1",
    "/soyo": "/pics2",
    "/mygo": "http://example.com"
  },
  "ALLOWED_TYPES": ["jpg", "png", "jpeg", "bmp", "gif", "svg", "heic", "nef", "webp"],
  "ENABLE_AVIF": false,
  "ENABLE_EXTRA_PARAMS": false,
  "READ_BUFFER_SIZE": 4096,
  "CONCURRENCY": 262144,
  "DISABLE_KEEPALIVE": false
}

再挂载到容器内部即可。

于是,docker-compose.yml 也跟着改动:

version: "3.9"
services:
  
  webpgo:
    image: webpsh/webp-server-go
    environment:
      - MALLOC_ARENA_MAX=1
    volumes:
      - ./webpgo/config.json:/etc/config.json #配置文件,需提前创建
      - ./pics:/pics #本地图片路径
      - ./pics1:/pics1 #本地图片路径1
      - ./pics2:/pics2 #本地图片路径2
      - ./webpgo/exhaust:/opt/exhaust #压缩后的图片缓存
      - ./webpgo/metadata:/opt/metadata #压缩前后的图片元数据缓存
    ports:
      - 3333:3333
    restart: unless-stopped
    container_name: webpgo

安装完毕后,可以使用 Nginx 进行反代3

server {
    listen 443 ssl;
    http2 on;
    server_name example.com;

   #省略SSL配置
    
    location / {
        proxy_pass http://webpgo:3333;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_hide_header X-Powered-By;
        proxy_set_header HOST $http_host;
        # add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; #鉴于自用需要缓存,所以不启用这段。
    }
    access_log /home/wwwlogs/example.com.log;
}

接着,就可以使用 http://example.com/anon/xxx.jpg 访问到 /pics1 路径下名为 xxx.jpg 的图片了。

如果你是将图片保存在博客的 usr/upload 文件夹中,也可以直接反代这一路径:

    location /usr/upload {
        proxy_pass http://webpgo:3333;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_hide_header X-Powered-By;
        proxy_set_header HOST $http_host;
        # add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
    }

这样就可以在不改变图片链接的前提下使用 WebP Server Go。前提是你已经挂载了博客的 usr/upload 文件夹到 webpgo 中。

使用

其实安装完就可以直接开始使用了,没什么好写的东西了。但我测试时发现,这玩意还可以拿来反代任意图片,不受防盗链影响,比如 sina

例如在 IMG_MAP 配置中写成这样:

  "IMG_MAP": {
    "/sina": "https://wx1.sinaimg.cn/large"
  },

然后访问 http://example.com/sina/9b8c9418ly1hbsl6dpurej22fa1i01kx.jpg ,可以直接访问到 https://wx1.sinaimg.cn/large/9b8c9418ly1hbsl6dpurej22fa1i01kx.jpg 的图片!

或者是 bilibili 的视频封面:

  "IMG_MAP": {
    "/bili": "https://i0.hdslb.com/bfs/archive"
  },

然后访问 http://example.com/bili/6d1590d19238188da23755a083eba70f415af569.jpg ,也可以直接访问 https://i0.hdslb.com/bfs/archive/6d1590d19238188da23755a083eba70f415af569.jpg

也就是说,WebP Server Go 不仅能拿来压缩图片,还能当便捷反向(图片)代理使用!

只要服务器能下载到图片!

或者,如果你认为自己部署一个 WebP Server Go 很麻烦,或是使用纯静态的博客程序托管在 GitHub Pages 上没有服务器,那么可以尝试使用官方的云服务:WebP Cloud Services

打开官网后,点击 Try WebP Cloud 并使用 GitHub 账户授权登录。

登录后,即可来到 WebP Cloud Services 的控制台。点击屏幕右下方的 Create Proxy 按钮,创建一个反代配置。

选择一个地区(随便选,国内访问肯定是都慢的),在「Proxy Name」中填入备注用以区分,「Proxy Origin URL」中填入具体到图片路径的原链接。点击 Create 创建

这样,你就创建好了一个 WebP Cloud Services 的反代,只需要将 Proxy Address 提供的地址替换掉你原来的图片地址,就可以啦!

例如,原图片为:https://www.himiku.com/2023/09/21/650b1c28345c7.jpg

那么 WebP Cloud Services 反代的图片就应为:https://abcdef.webp.ee/2023/09/21/650b1c28345c7.jpg

WebP Cloud Services 除了国内连接速度可能不太好接受(使用了 Cloudflare 进行减速),再就是 WebP Cloud Services 是一个商业项目,其他方面都是要优于自建的。至少不用你准备足够大的硬盘空间来存放转换后的 WebP 图片,也无须担心 WebP Server Go 出 bug 后卡死你的机子了。如果有使用需求的话,就请准备好钱包吧!