差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
工具:编辑:herokuv2ray [2023-07-22 07:13] – [CloudFlare 免费翻墙工具] goldentianya工具:编辑:herokuv2ray [2024-01-23 07:11] (当前版本) – [X-UI 搭建] goldentianya
行 66: 行 66:
 ====== X-UI 搭建 ====== ====== X-UI 搭建 ======
 [[https://luori.xyz/index.php/45/|教程一]] [[https://5best1s.com/%E5%8F%AF%E8%A7%86%E5%8C%96%E7%AE%A1%E7%90%86%E9%9D%A2%E6%9D%BFx-ui/|教程二]] {{fa>angellist}} [[https://luori.xyz/index.php/45/|教程一]] [[https://5best1s.com/%E5%8F%AF%E8%A7%86%E5%8C%96%E7%AE%A1%E7%90%86%E9%9D%A2%E6%9D%BFx-ui/|教程二]] {{fa>angellist}}
 +
 +[[https://github.com/vaxilu/x-ui|Github 项目地址]] ([[https://seakfind.github.io/2021/10/10/X-UI/|Document]])
  
 x-ui 一键安装 x-ui 一键安装
行 115: 行 117:
  
 [[https://www.v2fly.org/config/overview.html|v2ray 使用文档]] [[https://www.v2fly.org/config/overview.html|v2ray 使用文档]]
 +
 +更新分流文件的命令,需要每年执行一次。
 +  wget https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat -O /usr/local/x-ui/bin/geosite.dat
  
 ++++ 路由设置 |  ++++ 路由设置 | 
行 141: 行 146:
   - 证书放在 <color #7092be>/etc/v2ray-agent/tls/ali.simperator.top.crt</color>,已有证书的话先保存到这个路径。   - 证书放在 <color #7092be>/etc/v2ray-agent/tls/ali.simperator.top.crt</color>,已有证书的话先保存到这个路径。
 ====== CloudFlare 免费翻墙工具 ====== ====== CloudFlare 免费翻墙工具 ======
-每秒的IP都变化。采用 simpinvest.eu.org 域名来实现这个机场。 
  
-进入 CF => Worker and Pages => create Worker+[[it:skills:cf机场|]]
  
-打开v2ray 添加vlessf服务,点击生成一个用户id,并复制到脚本的 userID 中去。+[[https://www.ip2world.com/|ip2world]] + 指纹浏览(HubStudio) 可以实现物理层面IP环境
  
-五个加速地址 +[[https://www.kuaidaili.com/free/|免费proxy]]
-<code | download> +
-cdn.anycast.eu.org +
-edgetunnel.anycast.eu.org +
-cdn-b100.xn--b6gac.eu.org +
-     cdn.xn--b6gac.eu.org +
- cdn-all.xn--b6gac.eu.org +
-</code> +
- +
- +
-++++ worker.js | +
- +
-<code | download> +
-// <!--GAMFC-->version base on commit 43fad05dcdae3b723c53c226f8181fc5bd47223e, time is 2023-06-22 15:20:02 UTC<!--GAMFC-END-->+
-// @ts-ignore +
-import { connect } from 'cloudflare:sockets'; +
- +
-// How to generate your own UUID: +
-// [Windows] Press "Win + R", input cmd and run:  Powershell -NoExit -Command "[guid]::NewGuid()" +
-let userID = 'd342d11e-d424-4583-b36e-524ab1f0afa4'; +
- +
-let proxyIP = ''; +
- +
- +
-if (!isValidUUID(userID)) { +
- throw new Error('uuid is not valid'); +
-+
- +
-export default { +
- /** +
- * @param {import("@cloudflare/workers-types").Request} request +
- * @param {{UUID: string, PROXYIP: string}} env +
- * @param {import("@cloudflare/workers-types").ExecutionContext} ctx +
- * @returns {Promise<Response>+
- */ +
- async fetch(request, env, ctx) { +
- try { +
- userID = env.UUID || userID; +
- proxyIP = env.PROXYIP || proxyIP; +
- const upgradeHeader = request.headers.get('Upgrade'); +
- if (!upgradeHeader || upgradeHeader !== 'websocket') { +
- const url = new URL(request.url); +
- switch (url.pathname) { +
- case '/': +
- return new Response(JSON.stringify(request.cf), { status: 200 }); +
- case `/${userID}`:+
- const vlessConfig = getVLESSConfig(userID, request.headers.get('Host')); +
- return new Response(`${vlessConfig}`,+
- status: 200, +
- headers:+
- "Content-Type": "text/plain;charset=utf-8", +
-+
- }); +
-+
- default: +
- return new Response('Not found', { status: 404 }); +
-+
- } else { +
- return await vlessOverWSHandler(request); +
-+
- } catch (err) { +
- /** @type {Error} */ let e = err; +
- return new Response(e.toString()); +
-+
- }, +
-}; +
- +
- +
- +
- +
-/** +
- *  +
- * @param {import("@cloudflare/workers-types").Request} request +
- */ +
-async function vlessOverWSHandler(request) { +
- +
- /** @type {import("@cloudflare/workers-types").WebSocket[]} */ +
- // @ts-ignore +
- const webSocketPair = new WebSocketPair(); +
- const [client, webSocket] = Object.values(webSocketPair); +
- +
- webSocket.accept(); +
- +
- let address = ''; +
- let portWithRandomLog = ''; +
- const log = (/** @type {string} */ info, /** @type {string | undefined} */ event) => { +
- console.log(`[${address}:${portWithRandomLog}] ${info}`, event || ''); +
- }; +
- const earlyDataHeader = request.headers.get('sec-websocket-protocol') || ''; +
- +
- const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log); +
- +
- /** @type {{ value: import("@cloudflare/workers-types").Socket | null}}*/ +
- let remoteSocketWapper = { +
- value: null, +
- }; +
- let udpStreamWrite = null; +
- let isDns = false; +
- +
- // ws --> remote +
- readableWebSocketStream.pipeTo(new WritableStream({ +
- async write(chunk, controller) { +
- if (isDns && udpStreamWrite) { +
- return udpStreamWrite(chunk); +
-+
- if (remoteSocketWapper.value) { +
- const writer = remoteSocketWapper.value.writable.getWriter() +
- await writer.write(chunk); +
- writer.releaseLock(); +
- return; +
-+
- +
- const { +
- hasError, +
- message, +
- portRemote = 443, +
- addressRemote = '', +
- rawDataIndex, +
- vlessVersion = new Uint8Array([0, 0]), +
- isUDP, +
- } = processVlessHeader(chunk, userID); +
- address = addressRemote; +
- portWithRandomLog = `${portRemote}--${Math.random()} ${isUDP ? 'udp ' : 'tcp ' +
- } `; +
- if (hasError) { +
- // controller.error(message); +
- throw new Error(message); // cf seems has bug, controller.error will not end stream +
- // webSocket.close(1000, message); +
- return; +
-+
- // if UDP but port not DNS port, close it +
- if (isUDP) { +
- if (portRemote === 53) { +
- isDns = true; +
- } else { +
- // controller.error('UDP proxy only enable for DNS which is port 53'); +
- throw new Error('UDP proxy only enable for DNS which is port 53'); // cf seems has bug, controller.error will not end stream +
- return; +
-+
-+
- // ["version", "附加信息长度 N"] +
- const vlessResponseHeader = new Uint8Array([vlessVersion[0], 0]); +
- const rawClientData = chunk.slice(rawDataIndex); +
- +
- // TODO: support udp here when cf runtime has udp support +
- if (isDns) { +
- const { write } = await handleUDPOutBound(webSocket, vlessResponseHeader, log); +
- udpStreamWrite = write; +
- udpStreamWrite(rawClientData); +
- return; +
-+
- handleTCPOutBound(remoteSocketWapper, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log); +
- }, +
- close() { +
- log(`readableWebSocketStream is close`); +
- }, +
- abort(reason) { +
- log(`readableWebSocketStream is abort`, JSON.stringify(reason)); +
- }, +
- })).catch((err) => { +
- log('readableWebSocketStream pipeTo error', err); +
- }); +
- +
- return new Response(null,+
- status: 101, +
- // @ts-ignore +
- webSocket: client, +
- }); +
-+
- +
-/** +
- * Handles outbound TCP connections. +
- * +
- * @param {any} remoteSocket  +
- * @param {string} addressRemote The remote address to connect to. +
- * @param {number} portRemote The remote port to connect to. +
- * @param {Uint8Array} rawClientData The raw client data to write. +
- * @param {import("@cloudflare/workers-types").WebSocket} webSocket The WebSocket to pass the remote socket to. +
- * @param {Uint8Array} vlessResponseHeader The VLESS response header. +
- * @param {function} log The logging function. +
- * @returns {Promise<void>} The remote socket. +
- */ +
-async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log,) { +
- async function connectAndWrite(address, port) { +
- /** @type {import("@cloudflare/workers-types").Socket} */ +
- const tcpSocket = connect({ +
- hostname: address, +
- port: port, +
- }); +
- remoteSocket.value = tcpSocket; +
- log(`connected to ${address}:${port}`); +
- const writer = tcpSocket.writable.getWriter(); +
- await writer.write(rawClientData); // first write, nomal is tls client hello +
- writer.releaseLock(); +
- return tcpSocket; +
-+
- +
- // if the cf connect tcp socket have no incoming data, we retry to redirect ip +
- async function retry() { +
- const tcpSocket = await connectAndWrite(proxyIP || addressRemote, portRemote) +
- // no matter retry success or not, close websocket +
- tcpSocket.closed.catch(error => { +
- console.log('retry tcpSocket closed error', error); +
- }).finally(() => { +
- safeCloseWebSocket(webSocket); +
- }) +
- remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, null, log); +
-+
- +
- const tcpSocket = await connectAndWrite(addressRemote, portRemote); +
- +
- // when remoteSocket is ready, pass to websocket +
- // remote--> ws +
- remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, retry, log); +
-+
- +
-/** +
- *  +
- * @param {import("@cloudflare/workers-types").WebSocket} webSocketServer +
- * @param {string} earlyDataHeader for ws 0rtt +
- * @param {(info: string)=> void} log for ws 0rtt +
- */ +
-function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) { +
- let readableStreamCancel = false; +
- const stream = new ReadableStream({ +
- start(controller) { +
- webSocketServer.addEventListener('message', (event) => { +
- if (readableStreamCancel) { +
- return; +
-+
- const message = event.data; +
- controller.enqueue(message); +
- }); +
- +
- // The event means that the client closed the client -> server stream. +
- // However, the server -> client stream is still open until you call close() on the server side. +
- // The WebSocket protocol says that a separate close message must be sent in each direction to fully close the socket. +
- webSocketServer.addEventListener('close', () => { +
- // client send close, need close server +
- // if stream is cancel, skip controller.close +
- safeCloseWebSocket(webSocketServer); +
- if (readableStreamCancel) { +
- return; +
-+
- controller.close(); +
-+
- ); +
- webSocketServer.addEventListener('error', (err) => { +
- log('webSocketServer has error'); +
- controller.error(err); +
-+
- ); +
- // for ws 0rtt +
- const { earlyData, error } = base64ToArrayBuffer(earlyDataHeader); +
- if (error) { +
- controller.error(error); +
- } else if (earlyData) { +
- controller.enqueue(earlyData); +
-+
- }, +
- +
- pull(controller) { +
- // if ws can stop read if stream is full, we can implement backpressure +
- // https://streams.spec.whatwg.org/#example-rs-push-backpressure +
- }, +
- cancel(reason) { +
- // 1. pipe WritableStream has error, this cancel will called, so ws handle server close into here +
- // 2. if readableStream is cancel, all controller.close/enqueue need skip, +
- // 3. but from testing controller.error still work even if readableStream is cancel +
- if (readableStreamCancel) { +
- return; +
-+
- log(`ReadableStream was canceled, due to ${reason}`) +
- readableStreamCancel = true; +
- safeCloseWebSocket(webSocketServer); +
-+
- }); +
- +
- return stream; +
- +
-+
- +
-// https://xtls.github.io/development/protocols/vless.html +
-// https://github.com/zizifn/excalidraw-backup/blob/main/v2ray-protocol.excalidraw +
- +
-/** +
- *  +
- * @param { ArrayBuffer} vlessBuffer  +
- * @param {string} userID  +
- * @returns  +
- */ +
-function processVlessHeader( +
- vlessBuffer, +
- userID +
-) { +
- if (vlessBuffer.byteLength < 24) { +
- return { +
- hasError: true, +
- message: 'invalid data', +
- }; +
-+
- const version = new Uint8Array(vlessBuffer.slice(0, 1)); +
- let isValidUser = false; +
- let isUDP = false; +
- if (stringify(new Uint8Array(vlessBuffer.slice(1, 17))) === userID) { +
- isValidUser = true; +
-+
- if (!isValidUser) { +
- return { +
- hasError: true, +
- message: 'invalid user', +
- }; +
-+
- +
- const optLength = new Uint8Array(vlessBuffer.slice(17, 18))[0]; +
- //skip opt for now +
- +
- const command = new Uint8Array( +
- vlessBuffer.slice(18 + optLength, 18 + optLength + 1) +
- )[0]; +
- +
- // 0x01 TCP +
- // 0x02 UDP +
- // 0x03 MUX +
- if (command === 1) { +
- } else if (command === 2) { +
- isUDP = true; +
- } else { +
- return { +
- hasError: true, +
- message: `command ${command} is not support, command 01-tcp,02-udp,03-mux`, +
- }; +
-+
- const portIndex = 18 + optLength + 1; +
- const portBuffer = vlessBuffer.slice(portIndex, portIndex + 2); +
- // port is big-Endian in raw data etc 80 == 0x005d +
- const portRemote = new DataView(portBuffer).getUint16(0); +
- +
- let addressIndex = portIndex + 2; +
- const addressBuffer = new Uint8Array( +
- vlessBuffer.slice(addressIndex, addressIndex + 1) +
- ); +
- +
- // 1--> ipv4  addressLength =4 +
- // 2--> domain name addressLength=addressBuffer[1] +
- // 3--> ipv6  addressLength =16 +
- const addressType = addressBuffer[0]; +
- let addressLength = 0; +
- let addressValueIndex = addressIndex + 1; +
- let addressValue = ''; +
- switch (addressType) { +
- case 1: +
- addressLength = 4; +
- addressValue = new Uint8Array( +
- vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength) +
- ).join('.'); +
- break; +
- case 2: +
- addressLength = new Uint8Array( +
- vlessBuffer.slice(addressValueIndex, addressValueIndex + 1) +
- )[0]; +
- addressValueIndex += 1; +
- addressValue = new TextDecoder().decode( +
- vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength) +
- ); +
- break; +
- case 3: +
- addressLength = 16; +
- const dataView = new DataView( +
- vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength) +
- ); +
- // 2001:0db8:85a3:0000:0000:8a2e:0370:7334 +
- const ipv6 = []; +
- for (let i = 0; i < 8; i++) { +
- ipv6.push(dataView.getUint16(i * 2).toString(16)); +
-+
- addressValue = ipv6.join(':'); +
- // seems no need add [] for ipv6 +
- break; +
- default: +
- return { +
- hasError: true, +
- message: `invild  addressType is ${addressType}`, +
- }; +
-+
- if (!addressValue) { +
- return { +
- hasError: true, +
- message: `addressValue is empty, addressType is ${addressType}`, +
- }; +
-+
- +
- return { +
- hasError: false, +
- addressRemote: addressValue, +
- addressType, +
- portRemote, +
- rawDataIndex: addressValueIndex + addressLength, +
- vlessVersion: version, +
- isUDP, +
- }; +
-+
- +
- +
-/** +
- *  +
- * @param {import("@cloudflare/workers-types").Socket} remoteSocket  +
- * @param {import("@cloudflare/workers-types").WebSocket} webSocket  +
- * @param {ArrayBuffer} vlessResponseHeader  +
- * @param {(() => Promise<void>null} retry +
- * @param {*} log  +
- */ +
-async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) { +
- // remote--> ws +
- let remoteChunkCount = 0; +
- let chunks = []+
- /** @type {ArrayBuffer | null} */ +
- let vlessHeader = vlessResponseHeader; +
- let hasIncomingData = false; // check if remoteSocket has incoming data +
- await remoteSocket.readable +
- .pipeTo( +
- new WritableStream({ +
- start() { +
- }, +
- /** +
- *  +
- * @param {Uint8Array} chunk  +
- * @param {*} controller  +
- */ +
- async write(chunk, controller) { +
- hasIncomingData = true; +
- // remoteChunkCount++; +
- if (webSocket.readyState !== WS_READY_STATE_OPEN) { +
- controller.error( +
- 'webSocket.readyState is not open, maybe close' +
- ); +
-+
- if (vlessHeader) { +
- webSocket.send(await new Blob([vlessHeader, chunk]).arrayBuffer()); +
- vlessHeader = null; +
- } else { +
- // seems no need rate limit this, CF seems fix this??.. +
- // if (remoteChunkCount > 20000) { +
- // // cf one package is 4096 byte(4kb),  4096 * 20000 = 80M +
- // await delay(1); +
- // } +
- webSocket.send(chunk); +
-+
- }, +
- close() { +
- log(`remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData}`); +
- // safeCloseWebSocket(webSocket); // no need server close websocket frist for some case will casue HTTP ERR_CONTENT_LENGTH_MISMATCH issue, client will send close event anyway. +
- }, +
- abort(reason) { +
- console.error(`remoteConnection!.readable abort`, reason); +
- }, +
- }) +
-+
- .catch((error) => { +
- console.error( +
- `remoteSocketToWS has exception `, +
- error.stack || error +
- ); +
- safeCloseWebSocket(webSocket); +
- }); +
- +
- // seems is cf connect socket have error, +
- // 1. Socket.closed will have error +
- // 2. Socket.readable will be close without any data coming +
- if (hasIncomingData === false && retry) { +
- log(`retry`) +
- retry(); +
-+
-+
- +
-/** +
- *  +
- * @param {string} base64Str  +
- * @returns  +
- */ +
-function base64ToArrayBuffer(base64Str) { +
- if (!base64Str) { +
- return { error: null }; +
-+
- try { +
- // go use modified Base64 for URL rfc4648 which js atob not support +
- base64Str = base64Str.replace(/-/g, '+').replace(/_/g, '/'); +
- const decode = atob(base64Str); +
- const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0)); +
- return { earlyData: arryBuffer.buffer, error: null }; +
- } catch (error) { +
- return { error }; +
-+
-+
- +
-/** +
- * This is not real UUID validation +
- * @param {string} uuid  +
- */ +
-function isValidUUID(uuid) { +
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; +
- return uuidRegex.test(uuid); +
-+
- +
-const WS_READY_STATE_OPEN = 1; +
-const WS_READY_STATE_CLOSING = 2; +
-/** +
- * Normally, WebSocket will not has exceptions when close. +
- * @param {import("@cloudflare/workers-types").WebSocket} socket +
- */ +
-function safeCloseWebSocket(socket) { +
- try { +
- if (socket.readyState === WS_READY_STATE_OPEN || socket.readyState === WS_READY_STATE_CLOSING) { +
- socket.close(); +
-+
- } catch (error) { +
- console.error('safeCloseWebSocket error', error); +
-+
-+
- +
-const byteToHex = []; +
-for (let i = 0; i < 256; ++i) { +
- byteToHex.push((i + 256).toString(16).slice(1)); +
-+
-function unsafeStringify(arr, offset = 0) { +
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); +
-+
-function stringify(arr, offset = 0) { +
- const uuid = unsafeStringify(arr, offset); +
- if (!isValidUUID(uuid)) { +
- throw TypeError("Stringified UUID is invalid"); +
-+
- return uuid; +
-+
- +
- +
-/** +
- *  +
- * @param {import("@cloudflare/workers-types").WebSocket} webSocket  +
- * @param {ArrayBuffer} vlessResponseHeader  +
- * @param {(string)=> void} log  +
- */ +
-async function handleUDPOutBound(webSocket, vlessResponseHeader, log) { +
- +
- let isVlessHeaderSent = false; +
- const transformStream = new TransformStream({ +
- start(controller) { +
- +
- }, +
- transform(chunk, controller) { +
- // udp message 2 byte is the the length of udp data +
- // TODO: this should have bug, beacsue maybe udp chunk can be in two websocket message +
- for (let index = 0; index < chunk.byteLength;) { +
- const lengthBuffer = chunk.slice(index, index + 2); +
- const udpPakcetLength = new DataView(lengthBuffer).getUint16(0); +
- const udpData = new Uint8Array( +
- chunk.slice(index + 2, index + 2 + udpPakcetLength) +
- ); +
- index = index + 2 + udpPakcetLength; +
- controller.enqueue(udpData); +
-+
- }, +
- flush(controller) { +
-+
- }); +
- +
- // only handle dns udp for now +
- transformStream.readable.pipeTo(new WritableStream({ +
- async write(chunk) { +
- const resp = await fetch('https://1.1.1.1/dns-query', +
-+
- method: 'POST', +
- headers:+
- 'content-type': 'application/dns-message', +
- }, +
- body: chunk, +
- }) +
- const dnsQueryResult = await resp.arrayBuffer(); +
- const udpSize = dnsQueryResult.byteLength; +
- // console.log([...new Uint8Array(dnsQueryResult)].map((x) => x.toString(16))); +
- const udpSizeBuffer = new Uint8Array([(udpSize >> 8) & 0xff, udpSize & 0xff]); +
- if (webSocket.readyState === WS_READY_STATE_OPEN) { +
- log(`doh success and dns message length is ${udpSize}`); +
- if (isVlessHeaderSent) { +
- webSocket.send(await new Blob([udpSizeBuffer, dnsQueryResult]).arrayBuffer()); +
- } else { +
- webSocket.send(await new Blob([vlessResponseHeader, udpSizeBuffer, dnsQueryResult]).arrayBuffer()); +
- isVlessHeaderSent = true; +
-+
-+
-+
- })).catch((error) => { +
- log('dns udp has error' + error) +
- }); +
- +
- const writer = transformStream.writable.getWriter(); +
- +
- return { +
- /** +
- *  +
- * @param {Uint8Array} chunk  +
- */ +
- write(chunk) { +
- writer.write(chunk); +
-+
- }; +
-+
- +
-/** +
- *  +
- * @param {string} userID  +
- * @param {string | null} hostName +
- * @returns {string} +
- */ +
-function getVLESSConfig(userID, hostName) { +
- const vlessMain = `vless://${userID}@${hostName}:443?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2048#${hostName}` +
- return ` +
-################################################################ +
-v2ray +
---------------------------------------------------------------- +
-${vlessMain} +
---------------------------------------------------------------- +
-################################################################ +
-clash-meta +
---------------------------------------------------------------- +
-- type: vless +
-  name: ${hostName} +
-  server: ${hostName} +
-  port: 443 +
-  uuid: ${userID} +
-  network: ws +
-  tls: true +
-  udp: false +
-  sni: ${hostName} +
-  client-fingerprint: chrome +
-  ws-opts: +
-    path: "/?ed=2048" +
-    headers: +
-      host: ${hostName} +
---------------------------------------------------------------- +
-################################################################ +
-`; +
-+
- +
-</code> +
- +
-+++++
  
 +====== Xray + ipv6 ======
  
 +不良林的这个文档 [[https://www.bulianglin.com/archives/ipv6.html|说明文档]] 演示了如何创建基于ipv6的socks以及vmess代理。
 ====== 夏时 Accelerator ====== ====== 夏时 Accelerator ======
  
行 805: 行 165:
   * [[https://www.onworks.net/zh-CN/|在线虚拟机]]   * [[https://www.onworks.net/zh-CN/|在线虚拟机]]
   * [[https://www.bxvv1.xyz|暴雪VPN]] 使用 ++ 推荐码 | 6993538623343247360 ++ 可免费长期使用   * [[https://www.bxvv1.xyz|暴雪VPN]] 使用 ++ 推荐码 | 6993538623343247360 ++ 可免费长期使用
 +
 +{{tag>vpn}}
  
  
工具/编辑/herokuv2ray.1690010009.txt.gz · 最后更改: 2023-07-22 07:13 由 goldentianya
回到顶部
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0