惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
量子位
G
Google Developers Blog
J
Java Code Geeks
N
Netflix TechBlog - Medium
博客园 - 聂微东
宝玉的分享
宝玉的分享
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
月光博客
月光博客
The Cloudflare Blog
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
雷峰网
雷峰网
M
MIT News - Artificial intelligence
T
Tailwind CSS Blog
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
博客园 - 三生石上(FineUI控件)
Microsoft Azure Blog
Microsoft Azure Blog
aimingoo的专栏
aimingoo的专栏
Martin Fowler
Martin Fowler
有赞技术团队
有赞技术团队
T
The Blog of Author Tim Ferriss

東风

豆包图片下载器:一键保存豆包对话里的图片 从vps到边缘函数-我都经历了什么? 新主题设计理念 博客后台和域名 我给博客加了AI审核评论功能 我给博客加了AI审核评论功能 把 RSS 监控搬到了 EdgeOne 上,这次带了个前端 评论等级系统——从庶民到太师的九品十八阶 评论等级系统——从庶民到太师的九品十八阶 给 D1 数据库加了个只读副本,评论 API 快了 30% 给 D1 数据库加了个只读副本,评论 API 快了 30% 我退订了 Kimi 和 MiniMax 的 Coding Plan 我退订了 Kimi 和 MiniMax 的 Coding Plan 写了一个 RSS 博客订阅自动监控工具 写了一个 RSS 博客订阅自动监控工具 飞书同步机器人 — 部署教程 飞书同步机器人 — 部署教程 给博客评论加个飞书通知 给博客评论加个飞书通知 飞书发布测试 飞书发布测试 1700公里的旅程 1700公里的旅程 1700公里的旅程 Hello World - 欢迎来到我的博客 Hello World - 欢迎来到我的博客
魔法玩具 alwaysdata
東风 · 2026-07-14 · via 東风

背景

现在想找一个免费、稳定的魔法玩具太难了,动辄各种错误、IP 污染,根本没法好好用。直到有天刷洋抖无意间看到 Alwaysdata。免费版给 1/4 核心和 128M 内存,跑不了什么大东西,但挂几个链接够用了。先看效果:

2026-07-14_095057_023

看个 4K 没问题。

准备工具

你需要一个干净的住宅 IP,风控值别太高。风控高的话注册时会让你绑卡。怎么换 IP 自己想办法,搜一下 proxy 相关工具就行。如果注册时弹了绑卡提示,换个 IP 重新来。我换了几个才成功。没弹绑卡提示的话,恭喜你,继续下一步。

实操

登录后台,点 Sites > Sites,你会看到自己的地址 xxxx.alwaysdata.net,这就是后面要用的访问地址。

点右侧 Modify > Configuration,把运行时从 PHP 改成 Node.js,Command 栏填 npm start,保存。

然后进 Advanced > Servers,点右上角 Add a service,Command 和 Monitoring command 都填 npm start,勾上 Paused。这样服务停止时也能自动保活,这步很重要。

编辑

在任意位置新建一个文件夹,创建以下文件:

  • index.html
  • index.js
  • package.json

打开你的 AI 工具,让它帮你写一个炫酷的欧美行业首页,保存为 index.html。

index.js 的内容:

const os = require('os');
const http = require('http');
const fs = require('fs');
const axios = require('axios');
const net = require('net');
const path = require('path');
const crypto = require('crypto');
const { Buffer } = require('buffer');
const { exec, execSync } = require('child_process');
const { pipeline } = require('stream');
const { WebSocket, createWebSocketStream } = require('ws');
const UUID = process.env.UUID || '8baa4f2b-9835-4747-82a1-560ebf25aabb';
const NEZHA_SERVER = process.env.NEZHA_SERVER || '';
const NEZHA_PORT = process.env.NEZHA_PORT || '';
const NEZHA_KEY = process.env.NEZHA_KEY || '';
const DOMAIN = process.env.DOMAIN || 'xxxx.alwaysdata.net';
const AUTO_ACCESS = process.env.AUTO_ACCESS !== 'false';
const WSPATH = process.env.WSPATH || UUID.slice(0, 8);
const SUB_PATH = process.env.SUB_PATH || 'xxxx';
const NAME = process.env.NAME || 'xxxx';
const PORT = process.env.PORT || 8403;

let ISP = '';
const GetISP = async () => {
  try {
    const res = await axios.get('https://api.ip.sb/geoip');
    const data = res.data;
    ISP = `${data.country_code}-${data.isp}`.replace(/ /g, '_');
  } catch (e) {
    ISP = 'Unknown';
  }
}
const ispPromise = GetISP();

const httpServer = http.createServer(async (req, res) => {
  if (req.url === '/') {
    const filePath = path.join(__dirname, 'index.html');
    fs.readFile(filePath, 'utf8', (err, content) => {
      if (err) {
        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.end('Hello world!');
        return;
      }
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content);
    });
    return;
  } else if (req.url === `/${SUB_PATH}`) {
    await ispPromise;
    const namePart = NAME ? `${NAME}-${ISP}` : ISP;
    const vlessURL = `vless://${UUID}@${DOMAIN}:443?encryption=none&security=tls&sni=${DOMAIN}&fp=chrome&type=ws&host=${DOMAIN}&path=%2F${WSPATH}#${namePart}`;
    const trojanURL = `trojan://${UUID}@${DOMAIN}:443?security=tls&sni=${DOMAIN}&fp=chrome&type=ws&host=${DOMAIN}&path=%2F${WSPATH}#${namePart}`;
    const subscription = vlessURL + '\n' + trojanURL;
    const base64Content = Buffer.from(subscription).toString('base64');
    
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end(base64Content + '\n');
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Not Found\n');
  }
});

const wss = new WebSocket.Server({ server: httpServer });
const uuid = UUID.replace(/-/g, "");
const uuidBuffer = Buffer.from(uuid, 'hex');
const trojanHash = crypto.createHash('sha224').update(UUID).digest('hex');

const dnsCache = new Map();
const DNS_CACHE_TTL = 300000;
const DNS_CACHE_MAX = 1000;
const DOH_ENDPOINTS = [
  'https://dns.google/resolve',
  'https://cloudflare-dns.com/dns-query',
];

function resolveHost(host) {
  return new Promise((resolve, reject) => {
    if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(host)) {
      resolve(host);
      return;
    }
    const cached = dnsCache.get(host);
    if (cached && Date.now() - cached.time < DNS_CACHE_TTL) {
      resolve(cached.ip);
      return;
    }
    let attempts = 0;
    function tryNextDNS() {
      if (attempts >= DOH_ENDPOINTS.length) {
        reject(new Error(`Failed to resolve ${host} with all DNS servers`));
        return;
      }
      const dohUrl = DOH_ENDPOINTS[attempts];
      attempts++;
      const dnsQuery = `${dohUrl}?name=${encodeURIComponent(host)}&type=A`;
      axios.get(dnsQuery, {
        timeout: 5000,
        headers: { 'Accept': 'application/dns-json' }
      })
      .then(response => {
        const data = response.data;
        if (data.Status === 0 && data.Answer && data.Answer.length > 0) {
          const ip = data.Answer.find(record => record.type === 1);
          if (ip) {
            if (dnsCache.size >= DNS_CACHE_MAX) {
              const now = Date.now();
              for (const [key, val] of dnsCache) {
                if (now - val.time >= DNS_CACHE_TTL) dnsCache.delete(key);
              }
              if (dnsCache.size >= DNS_CACHE_MAX) {
                const firstKey = dnsCache.keys().next().value;
                dnsCache.delete(firstKey);
              }
            }
            dnsCache.set(host, { ip: ip.data, time: Date.now() });
            resolve(ip.data);
            return;
          }
        }
        tryNextDNS();
      })
      .catch(error => {
        tryNextDNS();
      });
    }
    tryNextDNS();
  });
}

function connectToTarget(ws, host, port, initialData) {
  const duplex = createWebSocketStream(ws);
  const doConnect = (targetHost) => {
    net.connect({ host: targetHost, port }, function() {
      if (initialData && initialData.length > 0) {
        this.write(initialData);
      }
      duplex.on('error', () => {}).pipe(this).on('error', () => {}).pipe(duplex);
    }).on('error', () => {});
  };
  resolveHost(host).then(doConnect).catch(() => doConnect(host));
}

function handleVlessConnection(ws, msg) {
  const [VERSION] = msg;
  const id = msg.slice(1, 17);
  if (Buffer.compare(id, uuidBuffer) !== 0) return false;
  
  let i = msg.slice(17, 18).readUInt8() + 19;
  const port = msg.slice(i, i += 2).readUInt16BE(0);
  const ATYP = msg.slice(i, i += 1).readUInt8();
  const host = ATYP == 1 ? msg.slice(i, i += 4).join('.') :
    (ATYP == 2 ? new TextDecoder().decode(msg.slice(i + 1, i += 1 + msg.slice(i, i + 1).readUInt8())) :
    (ATYP == 3 ? msg.slice(i, i += 16).reduce((s, b, i, a) => (i % 2 ? s.concat(a.slice(i - 1, i + 1)) : s), []).map(b => b.readUInt16BE(0).toString(16)).join(':') : ''));
  ws.send(new Uint8Array([VERSION, 0]));
  connectToTarget(ws, host, port, msg.slice(i));
  return true;
}

function handleTrojanConnection(ws, msg) {
  try {
    if (msg.length < 58) return false;
    const receivedPasswordHash = msg.slice(0, 56).toString();
    if (trojanHash !== receivedPasswordHash) return false;
    
    let offset = 56;
    if (msg[offset] === 0x0d && msg[offset + 1] === 0x0a) {
      offset += 2;
    }
    
    const cmd = msg[offset];
    if (cmd !== 0x01) return false;
    offset += 1;
    const atyp = msg[offset];
    offset += 1;
    let host, port;
    if (atyp === 0x01) {
      host = msg.slice(offset, offset + 4).join('.');
      offset += 4;
    } else if (atyp === 0x03) {
      const hostLen = msg[offset];
      offset += 1;
      host = msg.slice(offset, offset + hostLen).toString();
      offset += hostLen;
    } else if (atyp === 0x04) {
      host = msg.slice(offset, offset + 16).reduce((s, b, i, a) => 
        (i % 2 ? s.concat(a.slice(i - 1, i + 1)) : s), [])
        .map(b => b.readUInt16BE(0).toString(16)).join(':');
      offset += 16;
    } else {
      return false;
    }
    
    port = msg.readUInt16BE(offset);
    offset += 2;
    
    if (offset < msg.length && msg[offset] === 0x0d && msg[offset + 1] === 0x0a) {
      offset += 2;
    }
    
    connectToTarget(ws, host, port, offset < msg.length ? msg.slice(offset) : null);
    return true;
  } catch (error) {
    return false;
  }
}

wss.on('connection', (ws, req) => {
  const reqUrl = req.url || '';
  if (!reqUrl.includes(`/${WSPATH}`)) {
    ws.close(1008, 'Forbidden');
    return;
  }
  const idleTimer = setTimeout(() => ws.close(1000, 'Idle timeout'), 30000);
  ws.once('message', msg => {
    clearTimeout(idleTimer);
    if (msg.length > 17 && msg[0] === 0) {
      const id = msg.slice(1, 17);
      const isVless = Buffer.compare(id, uuidBuffer) === 0;
      if (isVless) {
        if (!handleVlessConnection(ws, msg)) {
          ws.close();
        }
        return;
      }
    }
    if (!handleTrojanConnection(ws, msg)) {
      ws.close();
    }
  }).on('error', () => {});
});

const getDownloadUrl = () => {
  const arch = os.arch(); 
  if (arch === 'arm' || arch === 'arm64' || arch === 'aarch64') {
    if (!NEZHA_PORT) {
      return 'https://arm64.ssss.nyc.mn/v1';
    } else {
      return 'https://arm64.ssss.nyc.mn/agent';
    }
  } else {
    if (!NEZHA_PORT) {
      return 'https://amd64.ssss.nyc.mn/v1';
    } else {
      return 'https://amd64.ssss.nyc.mn/agent';
    }
  }
};

const downloadFile = async () => {
  if (!NEZHA_SERVER && !NEZHA_KEY) return;
  try {
    const url = getDownloadUrl();
    const response = await axios({
      method: 'get',
      url: url,
      responseType: 'stream'
    });
    const writer = fs.createWriteStream('npm');
    return new Promise((resolve, reject) => {
      pipeline(response.data, writer, (err) => {
        if (err) { reject(err); return; }
        console.log('npm download successfully');
        exec('chmod +x npm', (err) => {
          if (err) reject(err);
          else resolve();
        });
      });
    });
  } catch (err) {
    throw err;
  }
};

const runnz = async () => {
  try {
    const status = execSync('ps aux | grep -v "grep" | grep "./[n]pm"', { encoding: 'utf-8' });
    if (status.trim() !== '') {
      console.log('npm is already running, skip running...');
      return;
    }
  } catch (e) {}

  await downloadFile();
  let command = '';
  let tlsPorts = ['443', '8443', '2096', '2087', '2083', '2053'];
  
  if (NEZHA_SERVER && NEZHA_PORT && NEZHA_KEY) {
    const NEZHA_TLS = tlsPorts.includes(NEZHA_PORT) ? '--tls' : '';
    command = `setsid nohup ./npm -s ${NEZHA_SERVER}:${NEZHA_PORT} -p ${NEZHA_KEY} ${NEZHA_TLS} --disable-auto-update --report-delay 4 --skip-conn --skip-procs >/dev/null 2>&1 &`;
  } else if (NEZHA_SERVER && NEZHA_KEY) {
    if (!NEZHA_PORT) {
      const port = NEZHA_SERVER.includes(':') ? NEZHA_SERVER.split(':').pop() : '';
      const NZ_TLS = tlsPorts.includes(port) ? 'true' : 'false';
      const configYaml = `client_secret: ${NEZHA_KEY}
debug: false
disable_auto_update: true
disable_command_execute: false
disable_force_update: true
disable_nat: false
disable_send_query: false
gpu: false
insecure_tls: true
ip_report_period: 1800
report_delay: 4
server: ${NEZHA_SERVER}
skip_connection_count: true
skip_procs_count: true
temperature: false
tls: ${NZ_TLS}
use_gitee_to_upgrade: false
use_ipv6_country_code: false
uuid: ${UUID}`;
      fs.writeFileSync('config.yaml', configYaml);
    }
    command = `setsid nohup ./npm -c config.yaml >/dev/null 2>&1 &`;
  } else {
    console.log('NEZHA variable is empty, skip running');
    return;
  }

  try {
    exec(command, { shell: '/bin/bash' }, (err) => {
      if (err) console.error('npm running error:', err);
      else console.log('npm is running');
    });
  } catch (error) {
    console.error(`error: ${error}`);
  }   
}; 

async function addAccessTask() {
  if (!AUTO_ACCESS) return;
  if (!DOMAIN) return;
  const fullURL = `https://${DOMAIN}`;
  try {
    const res = await axios.post("https://oooo.serv00.net/add-url", {
      url: fullURL
    }, {
      headers: { 'Content-Type': 'application/json' }
    });
    console.log('Automatic Access Task added successfully');
  } catch (error) {}
}

const delFiles = () => {
  fs.unlink('npm', () => {});
  fs.unlink('config.yaml', () => {}); 
};

httpServer.listen(PORT, () => {
  runnz().catch(err => console.error('runnz error:', err.message));
  setTimeout(() => {
    delFiles();
  }, 180000);
  addAccessTask();
  console.log(`Server is running on port ${PORT}`);
});

package.json:

{
  "name": "nodews",
  "version": "1.0.0",
  "description": "Nodejs-server",
  "main": "index.js",
  "private": false,
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "ws": "^8.14.2",
    "axios": "^1.12.2"
  },
  "engines": {
    "node": ">=14"
  }
}

把以上代码分别保存为 index.js 和 package.json。代码来自大佬的项目,我做了一些优化。

用编辑器打开 index.js,改几个地方:

const UUID = process.env.UUID || '8baa4f2b-9835-4747-82a1-560ebf25aabb'

去 UUID 生成网站随便生成一个替换进去。

const DOMAIN = process.env.DOMAIN || 'xxxx.alwaysdata.net'

改成你刚才拿到的地址。

const SUB_PATH = process.env.SUB_PATH || 'xxxx';

订阅路径,比如访问 xxxx.alwaysdata.net/xxxx 就能拿到订阅。

const NAME = process.env.NAME || 'xxxx';

节点名称,随便填。

const PORT = process.env.PORT || 8403;

端口号,alwaysdata 要求在 8300-8499 之间,随便挑一个。

改完之后,到这里混淆一下代码,保存。

在文件夹地址栏输入 cmd,执行上传:

scp index.html index.js package.json xxxx@xxxx.alwaysdata.net:~

输入创建机器时设的SSH密码,上传成功后用然后用 ssh -p 22 xxxx@xxxx.alwaysdata.net输入npm i && npm start之后访问xxxx.alwaysdata.net/xxxx就能拿到订阅了。

使用 CDN 加速

登录 Cloudflare 后台,新建一个 Worker,粘贴以下代码:

/**
 * Cloudflare Workers - 节点反代 CDN 加速
 * 
 * 功能:
 *   - 反向代理 HTTP 请求(订阅地址等)
 *   - 自动代理 WebSocket 连接(VLESS / Trojan)
 *   - 支持多后端域名随机负载均衡
 *   - 自动故障转移(某个后端失败时尝试下一个)
 *   - 通过环境变量动态配置,无需改代码
 * 
 * 部署方式:
 *   1. Cloudflare Dashboard → Workers & Pages → 创建 Worker → 粘贴此代码
 *   2. 或使用 wrangler: npx wrangler deploy
 * 
 * 使用方式:
 *   - 将客户端的节点地址 / 订阅地址域名改为 Worker 的域名即可
 *   - 在 Worker 设置中添加环境变量 BACKEND_DOMAINS 可动态配置后端
 */

const DEFAULT_BACKENDS = [
  'xxxx.alwaysdata.net',
];

function getRandomItem(array) {
  return array[Math.floor(Math.random() * array.length)];
}

function getBackends(env) {
  if (env.BACKEND_DOMAINS) {
    const list = env.BACKEND_DOMAINS.split(',')
      .map(d => d.trim())
      .filter(Boolean);
    if (list.length > 0) return list;
  }
  return DEFAULT_BACKENDS;
}

export default {
  async fetch(request, env, ctx) {
    try {
      const url = new URL(request.url);
      const backends = getBackends(env);
      const shuffled = [...backends].sort(() => Math.random() - 0.5);
      let lastError = null;

      for (const backend of shuffled) {
        try {
          const backendUrl = new URL(url.pathname + url.search, `https://${backend}`);
          const proxyRequest = new Request(backendUrl, request);
          proxyRequest.headers.set('Host', backend);

          const clientIP = request.headers.get('CF-Connecting-IP');
          if (clientIP) {
            proxyRequest.headers.set('X-Real-IP', clientIP);
            proxyRequest.headers.set('X-Forwarded-For', clientIP);
          }

          const response = await fetch(proxyRequest);

          if (response.status >= 500 && shuffled.length > 1) {
            lastError = new Error(`Backend ${backend} returned ${response.status}`);
            continue;
          }

          const newResponse = new Response(response.body, response);
          newResponse.headers.delete('X-Powered-By');
          newResponse.headers.delete('Server');
          newResponse.headers.delete('Via');
          newResponse.headers.set('X-CDN-Proxy', 'Cloudflare');

          return newResponse;
        } catch (err) {
          lastError = err;
          continue;
        }
      }

      return new Response('All backends unavailable', {
        status: 503,
        headers: { 'Content-Type': 'text/plain' },
      });
    } catch (error) {
      return new Response('Internal Server Error', {
        status: 500,
        headers: { 'Content-Type': 'text/plain' },
      });
    }
  },
};

DEFAULT_BACKENDS 里的地址换成你自己的就行。

以上就是全部折腾过程。该怎么玩全看你自己发挥了!