在 Serv00上反代 Huggingface 私有空间

躺平的咸鱼 发布于 3 天前 5 次阅读


rv00 疯狂杀号后,很多服务都已经不能部署了,这里分享一个通过 Serv00 反代 Huggingface 私有空间的脚本。
首先登录面板添加一个 Node.js 类型的域名,如果没有域名就先删除默认域名,如果有域名填写自定义域名即可。


然后添加后登录 SSH ,切换到新建域名的目录中 cd domains/域名/public_nodejs
运行 npm install http https jsonwebtoken axios http-proxy 先安装脚本需要的依赖
新建一个 app.js 把下面的脚本贴进去,注意修改config部分的user、space、token

const http = require('http');
const https = require('https');
const jwt = require('jsonwebtoken');
const axios = require('axios');
const httpProxy = require('http-proxy');

const config = {
  hf: {
    user: 'HF的用户名',
    space: 'HF的私有空间名',
    token: 'HF的Token'
  }
};

let jwtToken = '';

async function getTicket() {
  try {
    const { data } = await axios.get(`https://huggingface.co/api/spaces/${config.hf.user}/${config.hf.space}/jwt`, {
      headers: {
        'Authorization': `Bearer ${config.hf.token}`
      },
      httpsAgent: new https.Agent({ rejectUnauthorized: false })
    });

    jwtToken = data.token;
    return;
  } catch (error) {
    console.error('Failed to get JWT:', error.message);
    throw error;
  }
}

async function checkJwt() {
  if (!jwtToken) {
    return false;
  }

  try {
    const decoded = jwt.decode(jwtToken, { complete: true });
    const currentTime = Math.floor(Date.now() / 1000);
    return decoded.payload.exp - currentTime > 3600; // 检查是否超过 1 小时
  } catch (error) {
    console.error('Failed to decode JWT:', error.message);
    return false;
  }
}

async function getTicketLoop() {
  if (!jwtToken) {
    await getTicket();
  }
  setInterval(async () => {
    if (!await checkJwt()) {
      await getTicket();
    }
  }, 5 * 60 * 1000);
}

getTicketLoop();

const proxy = httpProxy.createProxyServer({
  secure: false,
  changeOrigin: true,
  target: {
    protocol: 'https:',
    host: `${config.hf.user}-${config.hf.space}.hf.space`,
    port: 443
  }
});


proxy.on('proxyReq', function(proxyReq, req, res, options) {
  let cookies = req.headers.cookie || '';
  let updatedCookies = cookies.split(';').filter(cookie => !cookie.trim().startsWith('spaces-jwt=')).join(';');
  updatedCookies += '; spaces-jwt=' + jwtToken;
  proxyReq.setHeader('Cookie', updatedCookies );
});
/*proxy.on("proxyRes", (proxyRes, req, res) => {
  const allowedHeaders = ["content-length", "content-type"];
  const headers = Object.keys(proxyRes.headers);
  headers.forEach((header) => {
    if (!allowedHeaders.includes(header.toLowerCase())) {
      delete proxyRes.headers[header];
    }
  });
});*/

const server = http.createServer((req, res) => {
  if (!jwtToken) {
    res.statusCode = 500;
    res.end('Failed to initialize JWT');
    return;
  }
  proxy.web(req, res, (err) => {
    res.writeHead(500, { 'Content-Type': 'text/plain' });
    res.end(`Something went wrong:${err}`);
  });
});

server.listen();

完成后删除public_nodejs下public里面的index.html 然后在面板重启网站即可。

如果有需要修改响应包头的可以修改我注释的 proxy.on("proxyRes", (proxyRes, req, res) => {}); 这部分。