
起因
我的 Hugo 博客用 APlayer + MetingJS 做音乐播放器,依赖第三方接口 api.injahow.cn 来解析网易云/QQ音乐的歌曲数据。某天播放器不出现了,控制台突然报错,按F12页面显示:
Fatal error: Uncaught RedisException: MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk...
原因不是博客代码的问题,而是 api.injahow.cn 这台第三方服务器自己的 Redis 数据库出了故障——磁盘写入失败,导致 Redis 拒绝执行任何写操作(包括接口用来做访问限流的计数功能),整个接口跟着崩溃,不过现在我要让音乐接口 “死者复生” ,看我的操作。
1.换下各种公共接口
既然是别人的meting服务器出问题了,找到了以下音乐解析器接口,我决定换以下四个公共接口:
meting-api.imsyy.top:直接连接失败(ERR_CONNECTION_CLOSED)。
meting-api-omega.vercel.app:数据能正常显示,可惜vercel域名被墙。
meting.mikus.ink:数据正常,但被 CORS 策略拦截。
meting.jinghuashang.cn:实测请求带参数后没有返回预期的 JSON 数据,不可用。
既然都有问题,我决定下一步。
2.部署meting-api服务
这里只需要:
一台能ping通的vps、一个域名。
打开你的vps(比如xshell、putty等登录终端),进行以下操作。
2-1.装docker
curl -fsSL https://get.docker.com | sh
其实我这里早装了。
验证方式是
docker -v
显示版本号安装成功。
2-2.安装拉取meting-api
docker run -d --name meting-api -p 3000:3000 --restart always intemd/meting-api:latest
2-3.验证本地是否能跑起来
curl "http://127.0.0.1:3000/api?server=netease&type=playlist&id=7640699765"
因为因为 API 实际路径是 /api,所以做了调整,输出为:
root@racknerd-6c465f:~# curl "http://127.0.0.1:3000/api?server=netease&type=playlist&id=7640699765"
[{"title":"Спокойная ночь","author":"Кино","pic":"https://p1.music.126.net/jrEDyug7ubULYf3UrXzHjg==/109951170416026069.jpg","url":"http://127.0.0.1:3000/api?server=netease&type=url&id=26710593","lrc":"http://127.0.0.1:3000/api?server=netease&type=lrc&id=26710593"}.......
代表成功。
3.申请免费域名
因为api接口需要域名解析到vps的ip,所以我选择的域名服务商是免费的DNSHE,这个域名是免费的,而且可以延长到十年内,自己随便填写一个记录名称前缀,记录内容就是你vps的ip。
填好后保存退出,等解析完成一会儿会有用。
4.配置 Nginx 反向代理
4-1.先确定你的vps系统,如果你的系统是debian/ubuntu一类的,一般是conf.d结构。
先确定Nginx用的那种结构:
ls /etc/nginx/
显示输出为:
root@racknerd-6c465f:~# ls /etc/nginx/
conf.d fastcgi_params mime.types modules nginx.conf scgi_params uwsgi_params
确定Nginx为D结构后,接下来:
nano /etc/nginx/conf.d/meting.conf
写入:
server {
listen 80;
server_name your domian(your domian代表是你刚刚申请的域名,后面我都用这个代替我申请的域名);
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' '*' always;
}
}
不过中间出现了小插曲,解决了。对于初步搭建meting-api的不用管,保存退出:Ctrl+X → Y → 回车就行。
然后检测并重载:
cat /etc/nginx/conf.d/meting.conf
输出为:
root@racknerd-6c465f:~# nano /etc/nginx/conf.d/meting.conf
root@racknerd-6c465f:~# cat /etc/nginx/conf.d/meting.conf
server {
listen 80;
server_name your domian;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' '*' always;
}
}
4-2.接下来检测并重载 Nginx
nginx -t
systemctl reload nginx
显示看到 syntax is ok 和 test is successful 就继续。
测速接口:
curl "http://your domian/api?server=netease&type=playlist&id=7640699765"
输出为:
root@racknerd-6c465f:~# curl "http://your domian/api?server=netease&type=playlist&id=7640699765"
[{"title":"Спокойная ночь","author":"Кино","pic":"https://p1.music.126.net/jrEDyug7ubULYf3UrXzHjg==/109951170416026069.jpg"......
即为成功。
apt update
apt install certbot python3-certbot-nginx -y
安装并申请证书,输入:
certbot --nginx -d your domian
输出为:
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/meting.tooyoungtoosimple.ccwu.cc/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/meting.tooyoungtoosimple.ccwu.cc/privkey.pem
Your cert will expire on 2026-11-14. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option. To non-interactively renew *all* of
your certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
提示你的证书申请成功,而且有效期到 2026-11-14。
再次输入测试https:
curl "https://your domian/api?server=netease&type=playlist&id=7640699765"
输出为:
root@racknerd-6c465f:~# curl "https://your aomian/api?server=netease&type=playlist&id=7640699765"
[{"title":"Спокойная ночь","author":"Кино","pic":"https://p1.music.126.net/jrEDyug7ubULYf3UrXzHjg==/109951170416026069.jpg","url":"http://your aomian/api?server=netease&type=url&id=26710593","lrc":"http://your domian/api?server=netease&type=lrc&id=26710593"}
4-3.解决url和lrc的http问题
主接口本身返回成功了(说明 HTTPS 通了),但有个细节要注意:返回内容里嵌套的 url 和 lrc 链接依然是 http:// 开头,不是 https://。这个项目有个特殊要求——它读取 X-Forwarded-Host 这个请求头来拼接返回链接里的协议和域名,而且格式比较特殊,需要写成 $scheme://$server_name 这样的形式,不是标准写法。
解决办法,编辑nano /etc/nginx/conf.d/meting.conf:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' '*' always;
}
在 proxy_set_header X-Forwarded-Proto $scheme; 这一行下面加一行:
proxy_set_header X-Forwarded-Host $scheme://$server_name;
保存退出:Ctrl+X → Y → 回车
检测并重载
nginx -t
systemctl reload nginx
重新测试:
curl "https://your domian/api?server=netease&type=playlist&id=7640699765"
结果显示url和lrc都有https了,成功完成。
5.解决CORS 头问题
我修改好后f12网页端提示:
Access to fetch at 'https://your domian/api?server=netease&type=playlist&id=7640699765&auth=undefined&r=0.5812098791672832' from origin 'https://www.zaqizaba.xyz' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Have the server send the header with a valid value.
解决办法是,在Ngnix除掉这三行:
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' '*' always;
变成:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $scheme://$server_name;
}
保存退出:Ctrl+X → Y → 回车
检测并重载
nginx -t
systemctl reload nginx
验证 CORS 头是否正常(只有一个了)
curl -I "https://your domian/api?server=netease&type=playlist&id=7640699765"
看输出里 Access-Control-Allow-Origin 这一行,应该只出现一次,值是单个 *,不是 *, *。
改完之后再回浏览器测试一次播放器,应该就没有 CORS 报错了。
输出为:
curl -I "https://your domian/api?server=netease&type=playlist&id=7640699765"
HTTP/1.1 200 OK
Server: nginx/1.27.5
Date: Sun, 16 Aug 2026 15:07:31 GMT
Content-Type: application/json; charset=UTF-8
Connection: keep-alive
access-control-allow-origin: *
输出为一个 *显示为成功。
6.限制自建接口
毕竟我是自己搭建的自建api接口,不是公共免费接口。我这个接口部署在我的vps上,不可能让别人都用,不然vps的api接口请求消耗的流量费用我hold不住。
这里可以这样做。给接口加一个简单的 Referer 检查。就是 只有从我的博客页面发起的请求才放行,其他来源直接拒绝(403)。
编辑配置文件
nano /etc/nginx/conf.d/meting.conf
在 443 端口那个 server {} 块里(跟 listen 443 ssl; 同级,location / 外面),加上这两行:
valid_referers none blocked www.zaqizaba.xyz zaqizaba.xyz;
if ($invalid_referer) {
return 403;
}
完整的 443 server 块应该长这样:
server {
server_name your domian;
valid_referers none blocked www.zaqizaba.xyz zaqizaba.xyz;
if ($invalid_referer) {
return 403;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $scheme://$server_name;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/your domian/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/your domian/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
保存生效:
nginx -t
systemctl reload nginx
测试是不是成功;
curl -H "Referer: https://evil-site.com" "https://your domian/api?server=netease&type=playlist&id=7640699765"
显示:
:~# curl -H "Referer: https://evil-site.com" "https://your domian/api?server=netease&type=playlist&id=7640699765"
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.5</center>
</body>
</html>
代表成功403,只有从你自己博客发起的请求才放行,其他来源直接返回 403。测试验证:带假 Referer 的请求确实被正确拦截了。
大功告成!!!现在将music shortcodes的原来出问题的api公共音乐接口:
var meting_api='https://api.injahow.cn/api?server=:server&type=:type&id=:id&auth=:auth&r=:r';
换成你用vps自建的api音乐接口:
var meting_api='https://your domian/api?server=:server&type=:type&id=:id&auth=:auth&r=:r';
这样,自己用vps搭建的音乐api接口就不用受第三方的Redis 数据库故障困扰了,完全自己掌握,并且出问题还可以排查。
