这两天上网冲浪的时候,发现了一个叫作「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 后卡死你的机子了。如果有使用需求的话,就请准备好钱包吧!
本文作者:mikusa
本文链接:https://www.himiku.com/archives/webp-server-go.html
封面出处:まにまに / ミツ蜂 #Pixiv
版权声明:所有文章除特别声明外均系本人自主创作,转载及引用请联系作者,并注明出处(作者、原文链接等)。
感谢推荐,已经在博客实装了
这个项目挺不错
为了让全站图片WebP化咱还特意写了个脚本在GithubActions将原始图片压缩,代价是一篇文章从撰写完成到上传网站起码花费45分钟
但是这个东西需要有一台vps…… (:3」∠)
其实可以试着薅一薅甲骨文的免费服务器(always free)
WebP还没完全替代PNG/JPG这个情况实在有点离谱。
不过AVIF还是慎用比较好,在Web端没事,落地到手机端和PC端很容易出现不识别的情况。
OωO 又拍云好像可以自动压成webp,之前我上传前还压缩一下图片,现在都直接传了,也不知道有没有生效2333
没钱买 CDN 了 (´இ皿இ`)
如果想用一台单独的服务器来作这个工作应该如何配置?比如我用static.himiku.com 作为静态文件域名,这个域名在另外一台服务器上反带主站,webpsh 怎么配置呢,有点绕
如果用 static.himiku.com 反代主站,那么直接在
IMG_PATH
配置里填域名就行,就不用映射图片文件夹了。就像这样:如果能实现多站点就好了,单独一台服务器做为反向服务,多域名多站点。
也可以啊,你的意思应该是只部署一个 webpgo 服务吧?假如你想用 a.net 反代 a.com
那么nginx反代的时候,a.net 的反代就这么写:
b.net 的反代就这么写:
感谢回复啊,我现在情况是主服务器上做了webp服务,二级域名作为静态域名绑定在第二个服务器上作为反向代理,那我只需要反带到主服务器上的webp就可以了吧,proxy_pass http://主服务器:3333;
是这样的
感谢你使用 WebP Cloud Services 的 Public Service 来输出 Gravatar 头像,并写了这篇文章来介绍 WebP Server Go (已经将这篇文章加入我们的文档上文章列表了: https://docs.webp.sh/related_articles/) :P
「也就是说,WebP Server Go 不仅能拿来压缩图片,还能当便捷反向(图片)代理使用!」
是的,我们甚至还有一个 SaaS 服务可以直接使用(减少自己维护 WebP Server Go 的压力):https://webp.se/
感谢大佬的项目!很好用!♪(・ω・)ノ
想顺便问一下,可以自已用 WebP Server Go 反代 gravatar 吗?可以的话要怎么写配置呢?
「可以自已用 WebP Server Go 反代 gravatar 吗」
可以的,由于 Gravatar 地址类似 https://www.gravatar.com/avatar/09eba3a443a7ea91cf818f6b27607d66,没有后缀名,所以 ALLOWED_TYPES 需要写 * ,一个可用的 config.json example 如下:
(好奇一下需要自建 Gravatar 反向代理的需求?(或者说 WebP Cloud Services 提供的公共反向代理在使用上有遇到什么问题咩?
顺便文章中:「 WebP Server Go 还有个内存泄漏的 Bug 还没修掉」
这个其实目前还好,我们测试发现如果用 jemalloc 配合 MALLOC_ARENA_MAX=1 其实已经可以将内存使用率限制到一个比较合理的范围了,详见文档: https://docs.webp.sh/usage/usage/ 中的部分。
(如果这样配置了还是遇到类似的问题的话,欢迎在 GitHub 上进行反馈~
感谢大佬!
自建主要是闲的,就是想自己也试试看。毕竟国内也有很多 Gravatar 反代,用了 CDN 更快更强(
WebP Cloud Services 没有啥问题的,只是因为套了 CF ,所以多少有一点点减速。此外没有任何问题,很好用!
好滴~
WebP Cloud Services 比较慢还有一个原因:我们的基础设施目前都在德国(Hetzner ARM64),我们目前发现大量的请求都会命中 Cloudflare 上美国 IAD 和 SJC 节点(大量的用户来自中国,其次是美国),所以对于中国访客来说,访问路径会是:中国电信/联通 -> Cloudflare 美国 -> Cloudflare 公网回源到德国源站(大概 160+ms) -> 源站
这个问题我们还在持续寻找合适的解决方案中,如果直接使用 Cloudflare 的 Load Balancer 分区回源我们的钱包遭不住,不使用 Cloudflare 的话可能国内用户体验会更差,或许我们会考虑将源站放在美国一份并继续使用 Cloudflare 来提升一下体验。
我发现我似乎对它反代图片的功能更感兴趣 ↀѡↀ
我的博客目前用的方案是DogeCloud自带的图片处理功能(转webp),然后CDN设一个阈值限制
它转过的图片会缓存起来,按理说cdn流量只会消耗一次,确实很可行 ↀѡↀ
感谢大佬的文章