mirror of
https://github.com/XTLS/Xray-docs-next.git
synced 2025-04-07 07:13:36 +03:00
Merge branch 'XTLS:main' into main
This commit is contained in:
commit
e76b91cc58
47 changed files with 3105 additions and 2247 deletions
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
|
@ -10,5 +10,6 @@ updates:
|
|||
schedule:
|
||||
interval: "daily"
|
||||
ignore:
|
||||
- dependency-name: "vue" #https://github.com/XTLS/Xray-docs-next/pull/465
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-patch"]
|
||||
|
|
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
|
@ -14,9 +14,10 @@ jobs:
|
|||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "18"
|
||||
- name: Install yarn
|
||||
- name: Install yarn and pnpm
|
||||
run: |
|
||||
npm install yarn@1.22.19 -g
|
||||
npm install -g pnpm
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||
|
@ -32,7 +33,7 @@ jobs:
|
|||
XRAY_DOCS_USE_VITE: "true"
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
run: |
|
||||
yarn install
|
||||
pnpm install
|
||||
yarn docs:build
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
|
|
|
@ -8,7 +8,7 @@ Project X 的文档托管在 [GitHub](https://github.com/XTLS/Xray-docs-next)
|
|||
|
||||
您可以通过以下步骤, 提交您对文档的改动:
|
||||
|
||||
1. 从 [project X 文档仓库](https://github.com/XTLS/Xray-docs-next) 打开仓库, 点击右上角的 fork, fork 一份文档仓库的镜像到您自己的 github 仓库.
|
||||
1. 从 [Project X 文档仓库](https://github.com/XTLS/Xray-docs-next) 打开仓库, 点击右上角的 fork, fork 一份文档仓库的镜像到您自己的 github 仓库.
|
||||
|
||||
2. 使用任何您喜欢的工具, 从您克隆的仓库获得文档的克隆, 如:
|
||||
|
||||
|
@ -24,11 +24,11 @@ git checkout -b your-branch
|
|||
|
||||
4. 在新分支上做修改。
|
||||
|
||||
注:在修改时请注意遵循 [中文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines)
|
||||
注:推荐 [中文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines)
|
||||
|
||||
5. 修改完成后,请格式化您的更改。建议使用 Prettier
|
||||
5. 修改完成后,请使用 [Prettier](https://prettier.io/docs/en/install.html) 格式化您的更改。
|
||||
|
||||
注:存在格式问题或不遵循中文文案排版指北的 PR,将有可能被拒绝。
|
||||
注:存在格式问题的 PR,将有可能被拒绝。
|
||||
|
||||
6. 提交修改,并推送到您的仓库中
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
# project X 的文档网站
|
||||
# Project X 的文档网站
|
||||
|
||||
## 关于网站
|
||||
|
||||
- 网站包含了 [project X 文档网站](https://xtls.github.io/) 所呈现的所有内容.
|
||||
- 网站包含了 [Project X 文档网站](https://xtls.github.io/) 所呈现的所有内容.
|
||||
|
||||
## 帮助我们改进网站
|
||||
|
||||
- 请参照 [改进文档步骤](https://xtls.github.io/document/document.html)
|
||||
- 请参照 [改进文档步骤](./CODE_OF_CONDUCT.md)
|
||||
|
||||
- 当成功向仓库提交了修改或 PR 被 merge 后, 会自动重新构建. 只需稍等片刻, 就可以在网站上看到修改的最新呈现.
|
||||
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
import { viteBundler } from "@vuepress/bundler-vite";
|
||||
import { webpackBundler } from "@vuepress/bundler-webpack";
|
||||
import { UserConfig, defineUserConfig } from "@vuepress/cli";
|
||||
// import { UserConfig, defineUserConfig } from "@vuepress/cli";
|
||||
import { UserConfig, defineUserConfig } from "vuepress/cli";
|
||||
import { searchPlugin } from "@vuepress/plugin-search";
|
||||
import markdownItFootnote from "markdown-it-footnote";
|
||||
import { defaultTheme } from "vuepress";
|
||||
import * as navbar from "./config/navbar";
|
||||
import { MermaidPlugin } from "./config/plugins/mermaidPlugin";
|
||||
import * as sidebar from "./config/sidebar";
|
||||
import { docsPlugin } from "./theme/index";
|
||||
import theme from './theme.js'
|
||||
import { registerComponentsPlugin } from '@vuepress/plugin-register-components'
|
||||
import process from 'node:process'
|
||||
// import { getDirname, path } from '@vuepress/utils'
|
||||
import { getDirname, path } from 'vuepress/utils'
|
||||
import { MermaidPlugin } from './plugins/mermaid/node/mermaid'
|
||||
|
||||
const __dirname = getDirname(import.meta.url)
|
||||
console.log('>>> __dirname -> ', __dirname)
|
||||
const isProduction = process.env.NODE_ENV === "production";
|
||||
const forMainRepo = process.env.XRAY_DOCS_MAIN_REPO === "true";
|
||||
const useVite = process.env.XRAY_DOCS_USE_VITE === "true";
|
||||
|
@ -28,6 +32,9 @@ export default defineUserConfig(<UserConfig>{
|
|||
},
|
||||
},
|
||||
}),
|
||||
registerComponentsPlugin({
|
||||
componentsDir: path.resolve(__dirname, './theme/components'),
|
||||
}),
|
||||
],
|
||||
base: forMainRepo ? "/" : "/Xray-docs-next/",
|
||||
locales: {
|
||||
|
@ -42,103 +49,7 @@ export default defineUserConfig(<UserConfig>{
|
|||
description: "Official document of Xray",
|
||||
},
|
||||
},
|
||||
theme: defaultTheme({
|
||||
...docsPlugin,
|
||||
smoothScroll: true,
|
||||
repo: "xtls/xray-core",
|
||||
docsRepo: "xtls/Xray-docs-next",
|
||||
docsDir: "docs",
|
||||
docsBranch: "main",
|
||||
editLinks: true,
|
||||
enableToggle: true,
|
||||
|
||||
themePlugins: {
|
||||
git: isProduction,
|
||||
},
|
||||
locales: {
|
||||
"/": {
|
||||
navbar: navbar.hans,
|
||||
repoLabel: "查看源码",
|
||||
editLinkText: "帮助我们改善此页面!",
|
||||
tip: "提示",
|
||||
warning: "注意",
|
||||
danger: "警告",
|
||||
lastUpdatedText: "最近更改",
|
||||
selectLanguageName: "简体中文",
|
||||
selectLanguageText: "多语言",
|
||||
selectLanguageAriaLabel: "多语言",
|
||||
sidebar: {
|
||||
"/config/": sidebar.getConfigSidebar(
|
||||
"特性详解",
|
||||
"基础配置",
|
||||
"入站代理",
|
||||
"出站代理",
|
||||
"底层传输",
|
||||
"/config/",
|
||||
),
|
||||
"/document/": sidebar.getDocumentSidebar(
|
||||
"快速入门文档",
|
||||
"/document/",
|
||||
),
|
||||
"/document/level-0/": sidebar.getDocumentLv0Sidebar(
|
||||
"小小白白话文",
|
||||
"/document/level-0/",
|
||||
),
|
||||
"/document/level-1/": sidebar.getDocumentLv1Sidebar(
|
||||
"入门技巧",
|
||||
"/document/level-1/",
|
||||
),
|
||||
"/document/level-2/": sidebar.getDocumentLv2Sidebar(
|
||||
"进阶技巧",
|
||||
"/document/level-2/",
|
||||
),
|
||||
"/development/": sidebar.getDevelopmentSidebar(
|
||||
"开发指南",
|
||||
"协议详解",
|
||||
"/development/",
|
||||
),
|
||||
},
|
||||
},
|
||||
"/en/": {
|
||||
repoLabel: "Source",
|
||||
editLinkText: "Help us improve this page on GitHub!",
|
||||
tip: "Tip",
|
||||
warning: "Warning",
|
||||
danger: "Danger",
|
||||
lastUpdatedText: "Last Updated",
|
||||
selectLanguageName: "English (WIP)",
|
||||
// TODO: translation
|
||||
sidebar: {
|
||||
"/en/config/": sidebar.getConfigSidebar(
|
||||
"Xray Features",
|
||||
"Config Reference",
|
||||
"Inbound Protocol",
|
||||
"Outbound Protocol",
|
||||
"Stream Transport Protocol",
|
||||
"/en/config/",
|
||||
),
|
||||
"/en/document/level-0/": sidebar.getDocumentLv0Sidebar(
|
||||
"Beginner Tutorial",
|
||||
"/en/document/level-0/",
|
||||
),
|
||||
"/en/document/level-1/": sidebar.getDocumentLv1Sidebar(
|
||||
"Getting Started Tips",
|
||||
"/en/document/level-1/",
|
||||
),
|
||||
"/en/document/level-2/": sidebar.getDocumentLv2Sidebar(
|
||||
"Advanced Documentation",
|
||||
"/en/document/level-2/",
|
||||
),
|
||||
"/en/development/": sidebar.getDevelopmentSidebar(
|
||||
"Developer Guide",
|
||||
"Protocol Details",
|
||||
"/en/development/",
|
||||
),
|
||||
},
|
||||
navbar: navbar.en,
|
||||
},
|
||||
},
|
||||
}),
|
||||
theme,
|
||||
head: [["link", { rel: "icon", href: `/logo.png` }]],
|
||||
markdown: {
|
||||
toc: {
|
||||
|
|
3
docs/.vuepress/config/index.ts
Executable file
3
docs/.vuepress/config/index.ts
Executable file
|
@ -0,0 +1,3 @@
|
|||
// export * from './head'
|
||||
export * from './navbar/index.js'
|
||||
export * from './sidebar/index.js'
|
|
@ -1,18 +0,0 @@
|
|||
import { NavbarConfig } from "@vuepress/theme-default";
|
||||
|
||||
export const hans: NavbarConfig = [
|
||||
{ text: "首页", link: "/" },
|
||||
{ text: "大史记", link: "/about/news.md" },
|
||||
{ text: "配置指南", link: "/config/" },
|
||||
{ text: "开发指南", link: "/development/" },
|
||||
{ text: "使用指南", link: "/document/" },
|
||||
];
|
||||
|
||||
// TODO: translation
|
||||
export const en: NavbarConfig = [
|
||||
{ text: "Homepage", link: "/en" },
|
||||
{ text: "Website History", link: "/en/about/news.md" },
|
||||
{ text: "Config Reference", link: "/en/config/" },
|
||||
{ text: "Developer Guide", link: "/en/development/" },
|
||||
{ text: "Quick Start", link: "/en/document/" },
|
||||
];
|
10
docs/.vuepress/config/navbar/en.ts
Executable file
10
docs/.vuepress/config/navbar/en.ts
Executable file
|
@ -0,0 +1,10 @@
|
|||
import { NavbarConfig } from '@vuepress/theme-default'
|
||||
|
||||
// TODO: translation
|
||||
export const navbarEn: NavbarConfig = [
|
||||
{ text: 'Homepage', link: '/en' },
|
||||
{ text: 'Website History', link: '/en/about/news.md' },
|
||||
{ text: 'Config Reference', link: '/en/config/' },
|
||||
{ text: 'Developer Guide', link: '/en/development/' },
|
||||
{ text: 'Quick Start', link: '/en/document/' },
|
||||
]
|
2
docs/.vuepress/config/navbar/index.ts
Executable file
2
docs/.vuepress/config/navbar/index.ts
Executable file
|
@ -0,0 +1,2 @@
|
|||
export * from './en.js'
|
||||
export * from './zh.js'
|
9
docs/.vuepress/config/navbar/zh.ts
Executable file
9
docs/.vuepress/config/navbar/zh.ts
Executable file
|
@ -0,0 +1,9 @@
|
|||
import { NavbarConfig } from '@vuepress/theme-default'
|
||||
|
||||
export const navbarZh: NavbarConfig = [
|
||||
{ text: '首页', link: '/' },
|
||||
{ text: '大史记', link: '/about/news.md' },
|
||||
{ text: '配置指南', link: '/config/' },
|
||||
{ text: '开发指南', link: '/development/' },
|
||||
{ text: '使用指南', link: '/document/' },
|
||||
]
|
|
@ -1,23 +0,0 @@
|
|||
// Reference: https://github.com/mermaid-js/mermaid
|
||||
|
||||
import { hash } from "@vuepress/utils";
|
||||
|
||||
const MermaidPlugin = function (md) {
|
||||
const fence = md.renderer.rules.fence;
|
||||
md.renderer.rules.fence = (...args) => {
|
||||
const [tokens, idx] = args;
|
||||
const { info } = tokens[idx];
|
||||
if (info.trim() === "mermaid") {
|
||||
const token = tokens[idx];
|
||||
const key = `mermaid_${hash(idx)}`;
|
||||
let { content } = token;
|
||||
return `<Mermaid identifier="${key}" graph="${encodeURI(
|
||||
content,
|
||||
)}"></Mermaid>`;
|
||||
}
|
||||
const rawCode = fence(...args);
|
||||
return `${rawCode}`;
|
||||
};
|
||||
};
|
||||
|
||||
export { MermaidPlugin };
|
|
@ -1,185 +0,0 @@
|
|||
import { SidebarConfigArray } from "@vuepress/theme-default";
|
||||
|
||||
export function getConfigSidebar(
|
||||
feature: string,
|
||||
config: string,
|
||||
inbound: string,
|
||||
outbound: string,
|
||||
transport: string,
|
||||
path: string
|
||||
): SidebarConfigArray {
|
||||
return [
|
||||
{
|
||||
text: feature,
|
||||
children: [
|
||||
path + "features/xtls.md",
|
||||
path + "features/fallback.md",
|
||||
path + "features/browser_dialer.md",
|
||||
path + "features/env.md",
|
||||
path + "features/multiple.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: config,
|
||||
children: [
|
||||
path + "",
|
||||
path + "log.md",
|
||||
path + "api.md",
|
||||
path + "dns.md",
|
||||
path + "fakedns.md",
|
||||
path + "inbound.md",
|
||||
path + "outbound.md",
|
||||
path + "policy.md",
|
||||
path + "reverse.md",
|
||||
path + "routing.md",
|
||||
path + "stats.md",
|
||||
path + "transport.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: inbound,
|
||||
children: [
|
||||
path + "inbounds/dokodemo.md",
|
||||
path + "inbounds/http.md",
|
||||
path + "inbounds/shadowsocks.md",
|
||||
path + "inbounds/socks.md",
|
||||
path + "inbounds/trojan.md",
|
||||
path + "inbounds/vless.md",
|
||||
path + "inbounds/vmess.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: outbound,
|
||||
children: [
|
||||
path + "outbounds/blackhole.md",
|
||||
path + "outbounds/dns.md",
|
||||
path + "outbounds/freedom.md",
|
||||
path + "outbounds/http.md",
|
||||
path + "outbounds/shadowsocks.md",
|
||||
path + "outbounds/socks.md",
|
||||
path + "outbounds/trojan.md",
|
||||
path + "outbounds/vless.md",
|
||||
path + "outbounds/vmess.md",
|
||||
path + "outbounds/wireguard.md",
|
||||
],
|
||||
},
|
||||
{
|
||||
text: transport,
|
||||
children: [
|
||||
path + "transports/grpc.md",
|
||||
path + "transports/h2.md",
|
||||
path + "transports/mkcp.md",
|
||||
path + "transports/quic.md",
|
||||
path + "transports/tcp.md",
|
||||
path + "transports/websocket.md",
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getDocumentSidebar(
|
||||
title: string,
|
||||
path: string
|
||||
): SidebarConfigArray {
|
||||
return [
|
||||
{
|
||||
text: title,
|
||||
children: [
|
||||
path + "install.md",
|
||||
path + "config.md",
|
||||
path + "command.md",
|
||||
path + "document.md",
|
||||
path + "level-0",
|
||||
path + "level-1",
|
||||
path + "level-2",
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getDocumentLv0Sidebar(
|
||||
title: string,
|
||||
path: string
|
||||
): SidebarConfigArray {
|
||||
return [
|
||||
{
|
||||
text: title,
|
||||
children: [
|
||||
path + "ch01-preface.md",
|
||||
path + "ch02-preparation.md",
|
||||
path + "ch03-ssh.md",
|
||||
path + "ch04-security.md",
|
||||
path + "ch05-webpage.md",
|
||||
path + "ch06-certificates.md",
|
||||
path + "ch07-xray-server.md",
|
||||
path + "ch08-xray-clients.md",
|
||||
path + "ch09-appendix.md",
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getDocumentLv1Sidebar(
|
||||
title: string,
|
||||
path: string
|
||||
): SidebarConfigArray {
|
||||
return [
|
||||
{
|
||||
text: title,
|
||||
children: [
|
||||
path + "fallbacks-lv1.md",
|
||||
path + "routing-lv1-part1.md",
|
||||
path + "routing-lv1-part2.md",
|
||||
path + "work.md",
|
||||
path + "fallbacks-with-sni.md",
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getDocumentLv2Sidebar(
|
||||
title: string,
|
||||
path: string
|
||||
): SidebarConfigArray {
|
||||
return [
|
||||
{
|
||||
text: title,
|
||||
children: [
|
||||
path + "transparent_proxy/transparent_proxy.md",
|
||||
path + "tproxy.md",
|
||||
path + "tproxy_ipv4_and_ipv6.md",
|
||||
path + "nginx_or_haproxy_tls_tunnel.md",
|
||||
path + "iptables_gid.md",
|
||||
path + "redirect.md",
|
||||
path + "warp.md",
|
||||
path + "traffic_stats.md",
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getDevelopmentSidebar(
|
||||
title: string,
|
||||
protocols: string,
|
||||
path: string
|
||||
): SidebarConfigArray {
|
||||
return [
|
||||
{
|
||||
text: title,
|
||||
children: [
|
||||
path + "intro/compile.md",
|
||||
path + "intro/design.md",
|
||||
path + "intro/guide.md",
|
||||
{
|
||||
text: protocols,
|
||||
children: [
|
||||
path + "protocols/vless.md",
|
||||
path + "protocols/vmess.md",
|
||||
path + "protocols/muxcool.md",
|
||||
path + "protocols/mkcp.md",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
147
docs/.vuepress/config/sidebar/en.ts
Executable file
147
docs/.vuepress/config/sidebar/en.ts
Executable file
|
@ -0,0 +1,147 @@
|
|||
import type { SidebarConfig } from '@vuepress/theme-default'
|
||||
|
||||
export const sidebarEn: SidebarConfig = {
|
||||
'/en/config/': [
|
||||
{
|
||||
text: 'feature',
|
||||
children: [
|
||||
'/en/config/features/xtls.md',
|
||||
'/en/config/features/fallback.md',
|
||||
'/en/config/features/browser_dialer.md',
|
||||
'/en/config/features/env.md',
|
||||
'/en/config/features/multiple.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'config',
|
||||
children: [
|
||||
'/en/config/README.md',
|
||||
'/en/config/log.md',
|
||||
'/en/config/api.md',
|
||||
'/en/config/dns.md',
|
||||
'/en/config/fakedns.md',
|
||||
'/en/config/inbound.md',
|
||||
'/en/config/outbound.md',
|
||||
'/en/config/policy.md',
|
||||
'/en/config/reverse.md',
|
||||
'/en/config/routing.md',
|
||||
'/en/config/stats.md',
|
||||
'/en/config/transport.md',
|
||||
'/en/config/metrics.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'inbound',
|
||||
children: [
|
||||
'/en/config/inbounds/dokodemo.md',
|
||||
'/en/config/inbounds/http.md',
|
||||
'/en/config/inbounds/shadowsocks.md',
|
||||
'/en/config/inbounds/socks.md',
|
||||
'/en/config/inbounds/trojan.md',
|
||||
'/en/config/inbounds/vless.md',
|
||||
'/en/config/inbounds/vmess.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'outbound',
|
||||
children: [
|
||||
'/en/config/outbounds/blackhole.md',
|
||||
'/en/config/outbounds/dns.md',
|
||||
'/en/config/outbounds/freedom.md',
|
||||
'/en/config/outbounds/http.md',
|
||||
'/en/config/outbounds/loopback.md',
|
||||
'/en/config/outbounds/shadowsocks.md',
|
||||
'/en/config/outbounds/socks.md',
|
||||
'/en/config/outbounds/trojan.md',
|
||||
'/en/config/outbounds/vless.md',
|
||||
'/en/config/outbounds/vmess.md',
|
||||
'/en/config/outbounds/wireguard.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'transport',
|
||||
children: [
|
||||
'/en/config/transports/domainsocket.md',
|
||||
'/en/config/transports/grpc.md',
|
||||
'/en/config/transports/h2.md',
|
||||
'/en/config/transports/mkcp.md',
|
||||
'/en/config/transports/quic.md',
|
||||
'/en/config/transports/tcp.md',
|
||||
'/en/config/transports/websocket.md',
|
||||
'/en/config/transports/httpupgrade.md'
|
||||
],
|
||||
},
|
||||
],
|
||||
'/en/document/': [
|
||||
{
|
||||
text: 'Quick Start',
|
||||
children: [
|
||||
'/en/document/README.md',
|
||||
'/en/document/install.md',
|
||||
'/en/document/config.md',
|
||||
'/en/document/command.md',
|
||||
'/en/document/document.md',
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Beginner Tutorial',
|
||||
children: [
|
||||
'/en/document/level-0/README.md',
|
||||
'/en/document/level-0/ch01-preface.md',
|
||||
'/en/document/level-0/ch02-preparation.md',
|
||||
'/en/document/level-0/ch03-ssh.md',
|
||||
'/en/document/level-0/ch04-security.md',
|
||||
'/en/document/level-0/ch05-webpage.md',
|
||||
'/en/document/level-0/ch06-certificates.md',
|
||||
'/en/document/level-0/ch07-xray-server.md',
|
||||
'/en/document/level-0/ch08-xray-clients.md',
|
||||
'/en/document/level-0/ch09-appendix.md',
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Getting Started Tips',
|
||||
children: [
|
||||
'/en/document/level-1/README.md',
|
||||
'/en/document/level-1/fallbacks-lv1.md',
|
||||
'/en/document/level-1/routing-lv1-part1.md',
|
||||
'/en/document/level-1/routing-lv1-part2.md',
|
||||
'/en/document/level-1/work.md',
|
||||
'/en/document/level-1/fallbacks-with-sni.md',
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Advanced Documentation',
|
||||
children: [
|
||||
'/en/document/level-2/README.md',
|
||||
'/en/document/level-2/transparent_proxy/transparent_proxy.md',
|
||||
'/en/document/level-2/tproxy.md',
|
||||
'/en/document/level-2/tproxy_ipv4_and_ipv6.md',
|
||||
'/en/document/level-2/nginx_or_haproxy_tls_tunnel.md',
|
||||
'/en/document/level-2/iptables_gid.md',
|
||||
'/en/document/level-2/redirect.md',
|
||||
'/en/document/level-2/warp.md',
|
||||
'/en/document/level-2/traffic_stats.md',
|
||||
]
|
||||
}
|
||||
],
|
||||
'/en/development/': [
|
||||
{
|
||||
text: 'Developer Guide',
|
||||
children: [
|
||||
'/en/development/README.md',
|
||||
'/en/development/intro/compile.md',
|
||||
'/en/development/intro/design.md',
|
||||
'/en/development/intro/guide.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Protocol Details',
|
||||
children: [
|
||||
'/en/development/protocols/vless.md',
|
||||
'/en/development/protocols/vmess.md',
|
||||
'/en/development/protocols/muxcool.md',
|
||||
'/en/development/protocols/mkcp.md',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
2
docs/.vuepress/config/sidebar/index.ts
Executable file
2
docs/.vuepress/config/sidebar/index.ts
Executable file
|
@ -0,0 +1,2 @@
|
|||
export * from './en.js'
|
||||
export * from './zh.js'
|
147
docs/.vuepress/config/sidebar/zh.ts
Executable file
147
docs/.vuepress/config/sidebar/zh.ts
Executable file
|
@ -0,0 +1,147 @@
|
|||
import type { SidebarConfig } from '@vuepress/theme-default'
|
||||
|
||||
export const sidebarZh: SidebarConfig = {
|
||||
'/config/': [
|
||||
{
|
||||
text: '特性详解',
|
||||
children: [
|
||||
'/config/features/xtls.md',
|
||||
'/config/features/fallback.md',
|
||||
'/config/features/browser_dialer.md',
|
||||
'/config/features/env.md',
|
||||
'/config/features/multiple.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '基础配置',
|
||||
children: [
|
||||
'/config/README.md',
|
||||
'/config/log.md',
|
||||
'/config/api.md',
|
||||
'/config/dns.md',
|
||||
'/config/fakedns.md',
|
||||
'/config/inbound.md',
|
||||
'/config/outbound.md',
|
||||
'/config/policy.md',
|
||||
'/config/reverse.md',
|
||||
'/config/routing.md',
|
||||
'/config/stats.md',
|
||||
'/config/transport.md',
|
||||
'/config/metrics.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '入站代理',
|
||||
children: [
|
||||
'/config/inbounds/dokodemo.md',
|
||||
'/config/inbounds/http.md',
|
||||
'/config/inbounds/shadowsocks.md',
|
||||
'/config/inbounds/socks.md',
|
||||
'/config/inbounds/trojan.md',
|
||||
'/config/inbounds/vless.md',
|
||||
'/config/inbounds/vmess.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '出站代理',
|
||||
children: [
|
||||
'/config/outbounds/blackhole.md',
|
||||
'/config/outbounds/dns.md',
|
||||
'/config/outbounds/freedom.md',
|
||||
'/config/outbounds/http.md',
|
||||
'/config/outbounds/loopback.md',
|
||||
'/config/outbounds/shadowsocks.md',
|
||||
'/config/outbounds/socks.md',
|
||||
'/config/outbounds/trojan.md',
|
||||
'/config/outbounds/vless.md',
|
||||
'/config/outbounds/vmess.md',
|
||||
'/config/outbounds/wireguard.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '底层传输',
|
||||
children: [
|
||||
'/config/transports/domainsocket.md',
|
||||
'/config/transports/grpc.md',
|
||||
'/config/transports/h2.md',
|
||||
'/config/transports/mkcp.md',
|
||||
'/config/transports/quic.md',
|
||||
'/config/transports/tcp.md',
|
||||
'/config/transports/websocket.md',
|
||||
'/config/transports/httpupgrade.md'
|
||||
],
|
||||
},
|
||||
],
|
||||
'/document/': [
|
||||
{
|
||||
text: '快速入门文档',
|
||||
children: [
|
||||
'/document/README.md',
|
||||
'/document/install.md',
|
||||
'/document/config.md',
|
||||
'/document/command.md',
|
||||
'/document/document.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '小小白白话文',
|
||||
children: [
|
||||
'/document/level-0/README.md',
|
||||
'/document/level-0/ch01-preface.md',
|
||||
'/document/level-0/ch02-preparation.md',
|
||||
'/document/level-0/ch03-ssh.md',
|
||||
'/document/level-0/ch04-security.md',
|
||||
'/document/level-0/ch05-webpage.md',
|
||||
'/document/level-0/ch06-certificates.md',
|
||||
'/document/level-0/ch07-xray-server.md',
|
||||
'/document/level-0/ch08-xray-clients.md',
|
||||
'/document/level-0/ch09-appendix.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '入门技巧',
|
||||
children: [
|
||||
'/document/level-1/README.md',
|
||||
'/document/level-1/fallbacks-lv1.md',
|
||||
'/document/level-1/routing-lv1-part1.md',
|
||||
'/document/level-1/routing-lv1-part2.md',
|
||||
'/document/level-1/work.md',
|
||||
'/document/level-1/fallbacks-with-sni.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '进阶技巧',
|
||||
children: [
|
||||
'/document/level-2/README.md',
|
||||
'/document/level-2/transparent_proxy/transparent_proxy.md',
|
||||
'/document/level-2/tproxy.md',
|
||||
'/document/level-2/tproxy_ipv4_and_ipv6.md',
|
||||
'/document/level-2/nginx_or_haproxy_tls_tunnel.md',
|
||||
'/document/level-2/iptables_gid.md',
|
||||
'/document/level-2/redirect.md',
|
||||
'/document/level-2/warp.md',
|
||||
'/document/level-2/traffic_stats.md',
|
||||
],
|
||||
}
|
||||
],
|
||||
'/development/': [
|
||||
{
|
||||
text: '开发指南',
|
||||
children: [
|
||||
'/development/README.md',
|
||||
'/development/intro/compile.md',
|
||||
'/development/intro/design.md',
|
||||
'/development/intro/guide.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '协议详解',
|
||||
children: [
|
||||
'/development/protocols/vless.md',
|
||||
'/development/protocols/vmess.md',
|
||||
'/development/protocols/muxcool.md',
|
||||
'/development/protocols/mkcp.md',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
9
docs/.vuepress/plugins/mermaid/helpers/darkmode.ts
Executable file
9
docs/.vuepress/plugins/mermaid/helpers/darkmode.ts
Executable file
|
@ -0,0 +1,9 @@
|
|||
// FIXME: Should correct handle dark selector
|
||||
export const getDarkmodeStatus = (): boolean => {
|
||||
const html = document.documentElement;
|
||||
|
||||
return (
|
||||
html.classList.contains("dark") ||
|
||||
html.getAttribute("data-theme") === "dark"
|
||||
);
|
||||
};
|
65
docs/.vuepress/plugins/mermaid/node/mermaid.ts
Executable file
65
docs/.vuepress/plugins/mermaid/node/mermaid.ts
Executable file
|
@ -0,0 +1,65 @@
|
|||
import type { PluginSimple } from "markdown-it";
|
||||
import type Renderer from "markdown-it/lib/renderer.js";
|
||||
|
||||
const mermaidRenderer: Renderer.RenderRule = (tokens: any, index: any) =>
|
||||
`<Mermaid id="mermaid-${index}" code="${encodeURI(
|
||||
tokens[index].content,
|
||||
)}"></Mermaid>`;
|
||||
|
||||
interface MermaidOptions {
|
||||
content: string;
|
||||
diagram?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const getMermaidContent = ({
|
||||
diagram = "mermaid",
|
||||
content,
|
||||
title = "",
|
||||
}: MermaidOptions): string => `\
|
||||
${title
|
||||
? `\
|
||||
---
|
||||
title: ${title}
|
||||
---
|
||||
|
||||
`
|
||||
: ""
|
||||
}\
|
||||
${diagram === "mermaid"
|
||||
? ""
|
||||
: `\
|
||||
${diagram}
|
||||
`
|
||||
}\
|
||||
${diagram === "mermaid" || diagram === "sankey-beta"
|
||||
? content
|
||||
: content
|
||||
.split("\n")
|
||||
.map((line) => (line ? ` ${line}` : ""))
|
||||
.join("\n")
|
||||
}\
|
||||
`;
|
||||
|
||||
const getMermaid = (options: MermaidOptions, index: number): string =>
|
||||
`<Mermaid id="mermaid-${index}" code="${encodeURI(getMermaidContent(options))}"${options.title ? ` title="${encodeURI(options.title)}"` : ""}></Mermaid>`;
|
||||
|
||||
export const MermaidPlugin: PluginSimple = (md) => {
|
||||
// Handle ```mermaid blocks
|
||||
const fence = md.renderer.rules.fence;
|
||||
|
||||
md.renderer.rules.fence = (...args): string => {
|
||||
const [tokens, index] = args;
|
||||
const { content, info } = tokens[index];
|
||||
|
||||
const fenceInfo = info.trim();
|
||||
|
||||
if (fenceInfo === "mermaid") return getMermaid({ content }, index);
|
||||
|
||||
const [name, ...rest] = fenceInfo.split(" ");
|
||||
|
||||
return fence!(...args);
|
||||
};
|
||||
|
||||
md.renderer.rules["mermaid"] = mermaidRenderer;
|
||||
};
|
73
docs/.vuepress/theme.ts
Executable file
73
docs/.vuepress/theme.ts
Executable file
|
@ -0,0 +1,73 @@
|
|||
import { defaultTheme } from '@vuepress/theme-default'
|
||||
// import { path, getDirname } from '@vuepress/utils'
|
||||
import { path, getDirname } from 'vuepress/utils'
|
||||
import process from 'node:process'
|
||||
import { navbarEn, navbarZh, sidebarEn, sidebarZh } from './config/index.js'
|
||||
|
||||
let __dirname = getDirname(import.meta.url)
|
||||
const isProduction = process.env.NODE_ENV === 'production'
|
||||
|
||||
export default defaultTheme({
|
||||
name: 'vuepress-theme-xray',
|
||||
smoothScroll: true,
|
||||
repo: 'xtls/xray-core',
|
||||
docsDir: 'docs',
|
||||
docsRepo: 'xtls/Xray-docs-next',
|
||||
docsBranch: 'main',
|
||||
editLinks: true,
|
||||
enableToggle: true,
|
||||
locales: {
|
||||
'/': {
|
||||
navbar: navbarZh,
|
||||
sidebar: sidebarZh,
|
||||
repoLabel: '查看源码',
|
||||
editLinkText: '帮助我们改善此页面!',
|
||||
tip: '提示',
|
||||
warning: '注意',
|
||||
danger: '警告',
|
||||
lastUpdatedText: '最近更改',
|
||||
selectLanguageName: '简体中文',
|
||||
selectLanguageText: '多语言',
|
||||
selectLanguageAriaLabel: '多语言',
|
||||
docsDir: 'docs',
|
||||
backToHome: 'back to home',
|
||||
openInNewWindow: 'open in new tag',
|
||||
toggleColorMode: 'toggle color mode',
|
||||
toggleSidebar: 'toggle side bar',
|
||||
},
|
||||
'/en/': {
|
||||
// TODO: translation
|
||||
sidebar: sidebarEn,
|
||||
navbar: navbarEn,
|
||||
selectLanguageName: 'English (WIP)',
|
||||
selectLanguageText: 'Multiple language',
|
||||
selectLanguageAriaLabel: 'Multiple language',
|
||||
editLinkText: 'Help us improve this page on GitHub!',
|
||||
lastUpdatedText: 'Last Updated',
|
||||
contributorsText: 'contributors',
|
||||
// repoLabel: 'Source',
|
||||
tip: 'Tip',
|
||||
warning: 'Warning',
|
||||
danger: 'Danger',
|
||||
|
||||
// 404 page
|
||||
notFound: [
|
||||
'这里什么都没有',
|
||||
'我们怎么到这来了?',
|
||||
'这是一个 404 页面',
|
||||
'看起来我们进入了错误的链接',
|
||||
],
|
||||
backToHome: 'back to home',
|
||||
openInNewWindow: 'open in new tag',
|
||||
toggleColorMode: 'toggle color mode',
|
||||
toggleSidebar: 'toggle side bar',
|
||||
},
|
||||
// logo: '/logo.png',
|
||||
|
||||
// sidebar: 'auto',
|
||||
|
||||
themePlugins: {
|
||||
git: isProduction,
|
||||
},
|
||||
},
|
||||
})
|
|
@ -1,4 +1,5 @@
|
|||
import { defineClientAppEnhance } from "@vuepress/client";
|
||||
// import { defineClientAppEnhance } from "@vuepress/client";
|
||||
import { defineClientAppEnhance } from "vuepress/client";
|
||||
import Tab from "./components/Tab.vue";
|
||||
import Tabs from "./components/Tabs.vue";
|
||||
import Mermaid from "./components/Mermaid.vue";
|
||||
|
|
|
@ -3,60 +3,81 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useMutationObserver } from "@vueuse/core";
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
h,
|
||||
onMounted,
|
||||
nextTick,
|
||||
toRef,
|
||||
ref,
|
||||
shallowRef,
|
||||
watch,
|
||||
reactive,
|
||||
nextTick,
|
||||
toRef
|
||||
} from "vue";
|
||||
import { useDarkMode } from "@vuepress/theme-default/lib/client";
|
||||
|
||||
import { getDarkmodeStatus } from "../../plugins/mermaid/helpers/darkmode.js";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Mermaid",
|
||||
props: {
|
||||
identifier: String,
|
||||
graph: String,
|
||||
},
|
||||
setup(props) {
|
||||
const dark = useDarkMode();
|
||||
const chartID = toRef(props, "identifier");
|
||||
const rawGraph = toRef(props, "graph");
|
||||
const html = reactive({ innerHtml: "" });
|
||||
onMounted(() => {
|
||||
nextTick(async function () {
|
||||
const mermaid = await import("mermaid");
|
||||
mermaid.default.initialize({
|
||||
startOnLoad: false,
|
||||
theme: dark.value ? "dark" : "default",
|
||||
});
|
||||
mermaid.default
|
||||
.render(chartID.value!, decodeURI(rawGraph.value!))
|
||||
.then(({ svg, bindFunctions }) => {
|
||||
html.innerHtml = svg;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
watch(dark, async () => {
|
||||
props: {
|
||||
id: { type: String, required: true },
|
||||
code: { type: String, required: true },
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const html = reactive({ innerHtml: "" });
|
||||
|
||||
const chartID = toRef(props, "id");
|
||||
const rawGraph = toRef(props, "code");
|
||||
|
||||
const isDarkmode = ref(false);
|
||||
|
||||
const renderMermaid = async (): Promise<void> => {
|
||||
const mermaid = await import("mermaid");
|
||||
|
||||
mermaid.default.initialize({
|
||||
theme: isDarkmode.value ? "dark" : "default",
|
||||
startOnLoad: false,
|
||||
theme: dark.value ? "dark" : "default",
|
||||
});
|
||||
mermaid.default
|
||||
.render(chartID.value!, decodeURI(rawGraph.value!))
|
||||
.then(({ svg, bindFunctions }) => {
|
||||
html.innerHtml = svg;
|
||||
});
|
||||
});
|
||||
|
||||
mermaid.default.render(chartID.value!, decodeURI(rawGraph.value!)).then(({ svg, bindFunctions }) => {
|
||||
html.innerHtml = svg;
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
isDarkmode.value = getDarkmodeStatus()
|
||||
nextTick(renderMermaid)
|
||||
})
|
||||
|
||||
// watch darkmode change
|
||||
if (typeof document !== 'undefined') {
|
||||
useMutationObserver(
|
||||
document.documentElement,
|
||||
() => {
|
||||
isDarkmode.value = getDarkmodeStatus();
|
||||
},
|
||||
{
|
||||
attributeFilter: ["class", "data-theme"],
|
||||
attributes: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
watch(isDarkmode, () => renderMermaid());
|
||||
|
||||
return {
|
||||
tag: chartID,
|
||||
payload: html,
|
||||
};
|
||||
payload: html
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { Theme } from "@vuepress/core";
|
||||
import { path } from "@vuepress/utils";
|
||||
// import { Theme } from "@vuepress/core";
|
||||
import { Theme } from "vuepress/core";
|
||||
// import { path } from "@vuepress/utils";
|
||||
import { path } from "vuepress/utils";
|
||||
import { defaultTheme } from "vuepress";
|
||||
|
||||
export const docsPlugin: Theme = (options, app) => {
|
||||
|
|
|
@ -83,9 +83,9 @@ footer: Licensed under CC-BY-SA 4.0 | Copyright 2020-Present Project X Community
|
|||
- 感谢提出有意义的建议和意见的朋友们.
|
||||
- 感谢 Telegram 群每一位帮助群友的朋友.
|
||||
|
||||
### 更多关于 project X
|
||||
### 更多关于 Project X
|
||||
|
||||
- 如果你想知道更多关于 project X 的足迹与成长, 请点击[这里](./about/news.md)
|
||||
- 如果你想知道更多关于 Project X 的足迹与成长, 请点击[这里](./about/news.md)
|
||||
|
||||
### License
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# metrics
|
||||
# Metrics
|
||||
|
||||
更直接(希望更好)的统计导出方式。
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ Freedom 是一个出站协议,可以用来向任意网络发送(正常的)
|
|||
"packets": "tlshello",
|
||||
"length": "100-200",
|
||||
"interval": "10-20" // 单位ms
|
||||
}
|
||||
},
|
||||
"proxyProtocol": 0
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -21,29 +22,19 @@ Freedom 是一个出站协议,可以用来向任意网络发送(正常的)
|
|||
> "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"<br>
|
||||
> "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
|
||||
|
||||
Xray-core v1.8.6 新增功能:<br>
|
||||
`"UseIPv6v4"` | `"UseIPv4v6"`<br>
|
||||
`"ForceIP"` | `"ForceIPv6v4"` | `"ForceIPv6"` | `"ForceIPv4v6"` | `"ForceIPv4"`
|
||||
|
||||
若不写此参数,或留空,默认值 `"AsIs"`。
|
||||
默认值 `"AsIs"`。
|
||||
|
||||
当目标地址为域名时,配置相应的值,Freedom 的行为模式如下:
|
||||
|
||||
- `"AsIs"`:Freedom 使用系统 DNS 同时查询 A 和 AAAA 记录获取 IP,向此域名发出连接。IPv4 或 IPv6 优先级由系统控制。
|
||||
- `"UseIP"`、`"UseIPv6v4"`、`"UseIPv6"`、`"UseIPv4v6"`、`"UseIPv4"`:使用 Xray-core [内置 DNS 服务器](../dns.md) 查询获取 IP,向此域名发出连接。
|
||||
- `"ForceIP"`、`"ForceIPv6v4"`、`"ForceIPv6"`、`"ForceIPv4v6"`、`"ForceIPv4"`:使用 Xray-core [内置 DNS 服务器](../dns.md) 查询获取 IP,向此域名发出连接。
|
||||
- 当使用 `"UseIP"` 系列值 或 `"ForceIP"` 系列值时,若没写 `"dns"` 配置,使用系统 DNS 同时查询 A 和 AAAA 记录获取 IP,向此域名发出连接。
|
||||
- 当使用 `"AsIs"` 时,Xray将直接使用系统栈发起连接,优先级与选择IP取决于系统设置。
|
||||
- 当填写其他值时,将使用 Xray-core [内置 DNS 服务器](../dns.md) 服务器进行解析。若不存在DNSObject,则使用系统DNS。若有多个符合条件的IP地址时,核心会随机选择一个IP作为目标IP。
|
||||
- `"IPv4"` 代表尝试仅使用IPv4进行连接,`"IPv4v6"` 代表尝试使用IPv4或IPv6连接,但对于双栈域名,尽量使用IPv4。(v4v6调换后同理,不再赘述)
|
||||
- 当在内置DNS设置了 `"queryStrategy"` 后,实际行为将会与这个选项取并,只有都被包含的IP类型才会被解析,如 `"queryStrategy": "UseIPv4"` `"domainStrategy": "UseIP"`,实际上等同于 `"domainStrategy": "UseIPv4"`。
|
||||
- 当使用 `"Use"` 开头的选项时,若解析结果不符合要求(如,域名只有IPv4解析结果但使用了UseIPv6),则会回落回AsIs。
|
||||
- 当使用 `"Force"` 开头的选项时,若解析结果不符合要求,则该连接会无法建立。
|
||||
|
||||
::: tip TIP 1
|
||||
当使用 `"UseIP"`、`"ForceIP"` 模式时,并且 [出站连接配置](../outbound.md#outboundobject) 中指定了 `sendThrough` 时,Freedom 会根据 `sendThrough` 的值自动判断所需的 IP 类型,IPv4 或 IPv6。
|
||||
:::
|
||||
|
||||
::: tip TIP 2
|
||||
当使用 `"UseIPv4"`、`"UseIPv6"` 或 `"ForceIPv4"`、`"ForceIPv6"` 模式时,Freedom 会只使用对应的 IPv4 或 IPv6 地址。当 `sendThrough` 指定了不匹配的本地地址时,将导致连接失败。
|
||||
:::
|
||||
|
||||
::: tip TIP 3
|
||||
`"UseIPv4"`、`"UseIPv6"` 和 `"ForceIPv4"`、`"ForceIPv6"` 的区别是,前者解析失败了会走 AsIs,后者解析失败了会被 block。这样整个 `domainStrategy` 都更加灵活了。
|
||||
当使用 `"UseIP"`、`"ForceIP"` 模式时,并且 [出站连接配置](../outbound.md#outboundobject) 中指定了 `sendThrough` 时,Freedom 会根据 `sendThrough` 的值自动判断所需的 IP 类型,IPv4 或 IPv6。若手动指定了单种IP类型(如UseIPv4),但与 `sendThrough` 指定的本地地址不匹配,将会导致连接失败。
|
||||
:::
|
||||
|
||||
> `redirect`: address_port
|
||||
|
@ -70,3 +61,9 @@ userLevel 的值, 对应 [policy](../policy.md#policyobject) 中 `level` 的值
|
|||
`"length"`:分片包长 (byte)
|
||||
|
||||
`"interval"`:分片间隔(ms)
|
||||
|
||||
> `proxyProtocol`: number
|
||||
|
||||
PROXY protocol 通常配合 `redirect` 重定向到开启了 PROXY protocol 协议的 Nginx 或其他后端服务中。如果后端服务不支持 PROXY protocol 协议,连接将会被断开。
|
||||
|
||||
proxyProtocol 的值为 PROXY protocol 版本号,可选 `1` 或 `2`,如不指定,默认为 `0` 不启用。
|
||||
|
|
57
docs/config/outbounds/loopback.md
Normal file
57
docs/config/outbounds/loopback.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Loopback
|
||||
|
||||
Loopback 是个出站数据协议,其作用为将经该出站传出的数据重新送入路由入站,以达到数据无需离开 Xray-core 即可再次被路由处理的效果。
|
||||
|
||||
## OutboundConfigurationObject
|
||||
|
||||
```json
|
||||
{
|
||||
"inboundTag": "TagUseAsInbound"
|
||||
}
|
||||
```
|
||||
|
||||
> `inboundTag`: string
|
||||
|
||||
用于重新路由的入站协议标识。
|
||||
|
||||
该标识可以在路由中用于 `inboundTag` ,表示该出站中的数据可以被对应的路由规则再次处理。
|
||||
|
||||
### 如何使用?
|
||||
|
||||
如果需要将已经通过路由规则分流过的流量再由其它路由规则做更细致的分流,比如由同一组路由规则分流后的 TCP 流量和 UDP 要走不同的出站,则可以使用 `loopback` 出站完成。
|
||||
|
||||
``` json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "loopback",
|
||||
"tag": "need-to-split",
|
||||
"settings": {
|
||||
"tag": "traffic-input" // 该 tag 在下方用于 RuleObject 的 inboundTag
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "tcp-output",
|
||||
// protocol, settings, streamSettings 之类的设置
|
||||
},
|
||||
{
|
||||
"tag": "udp-output",
|
||||
// protocol, settings, streamSettings 之类的设置
|
||||
}
|
||||
],
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["traffic-input"], // loopback 设定的 tag
|
||||
"network": "tcp",
|
||||
"outboundTag": "tcp-output"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["traffic-input"], // loopback 设定的 tag
|
||||
"network": "udp",
|
||||
"outboundTag": "udp-output"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
|
@ -23,6 +23,7 @@
|
|||
"publicKey": "PUBLIC_KEY"
|
||||
}
|
||||
],
|
||||
"kernelMode": true, // optional, default true if it's supported and permission is sufficient
|
||||
"mtu": 1420, // optional, default 1420
|
||||
"reserved": [1, 2, 3],
|
||||
"workers": 2, // optional, default runtime.NumCPU()
|
||||
|
@ -42,6 +43,15 @@
|
|||
|
||||
Wireguard 会在本地开启虚拟网卡 tun。使用一个或多个 IP 地址,支持 IPv6
|
||||
|
||||
> `kernelMode`: true | false
|
||||
|
||||
是否使用 Linux 内核的虚拟网卡 TUN。<br>
|
||||
需要系统支持且有 root 权限才能使用 Linux 内核的虚拟网卡 TUN,使用后会占用 IPv6 的 1023 号路由表。<br>
|
||||
|
||||
::: tip
|
||||
若 IPv6 的 1023 号路由表内已有路由条目,且 `kernelMode` 的值为 `true`,将无法正常使用。
|
||||
:::
|
||||
|
||||
> `mtu`: int
|
||||
|
||||
Wireguard 底层 tun 的分片大小。
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
"httpSettings": {},
|
||||
"quicSettings": {},
|
||||
"dsSettings": {},
|
||||
"grpcSettings": {}
|
||||
"grpcSettings": {},
|
||||
"httpupgradeSettings": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -54,6 +55,10 @@
|
|||
|
||||
针对 gRPC 连接的配置。
|
||||
|
||||
> `httpupgradeSettings`: [HttpUpgradeObject](./transports/httpupgrade.md)
|
||||
|
||||
针对 HTTPUpragde 连接的配置。
|
||||
|
||||
> `dsSettings`: [DomainSocketObject](./transports/domainsocket.md)
|
||||
|
||||
针对 Domain Socket 连接的配置。
|
||||
|
@ -74,6 +79,7 @@
|
|||
"quicSettings": {},
|
||||
"dsSettings": {},
|
||||
"grpcSettings": {},
|
||||
"httpupgradeSettings": {},
|
||||
"sockopt": {
|
||||
"mark": 0,
|
||||
"tcpMaxSeg": 1440,
|
||||
|
@ -88,14 +94,14 @@
|
|||
"tcpcongestion": "bbr",
|
||||
"interface": "wg0",
|
||||
"V6Only": false,
|
||||
"tcpWindowClamp": 600
|
||||
"tcpWindowClamp": 600,
|
||||
"tcpMptcp": false,
|
||||
"tcpNoDelay": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `network`: "tcp" | "ws" | "h2" | "grpc" | "quic" | "kcp"
|
||||
> `network`: "tcp" | "ws" | "h2" | "grpc" | "quic" | "kcp" | "httpupgrade"
|
||||
|
||||
连接的数据流所使用的传输方式类型,默认值为 `"tcp"`
|
||||
|
||||
|
@ -108,7 +114,7 @@
|
|||
是否启用传输层加密,支持的选项有
|
||||
|
||||
- `"none"` 表示不加密(默认值)
|
||||
- `"tls"` 表示使用 [TLS](https://en.wikipedia.org/wiki/base/transport_Layer_Security)。
|
||||
- `"tls"` 表示使用 [TLS](https://zh.wikipedia.org/wiki/%E5%82%B3%E8%BC%B8%E5%B1%A4%E5%AE%89%E5%85%A8%E6%80%A7%E5%8D%94%E5%AE%9A)。
|
||||
- `"reality"` 表示使用 REALITY。
|
||||
|
||||
> `tlsSettings`: [TLSObject](#tlsobject)
|
||||
|
@ -152,6 +158,11 @@ Reality 是目前最安全的传输加密方案, 且外部看来流量类型和
|
|||
|
||||
当前连接的 Domain socket 配置,仅当此连接使用 Domain socket 时有效。配置内容与上面的全局配置相同。
|
||||
|
||||
> `httpupgradeSettings`: [HttpUpgradeObject](./transports/httpupgrade.md)
|
||||
|
||||
当前连接的 HTTPUpragde 配置,仅当此连接使用 HTTPUpragde 时有效。配置内容与上面的全局配置相同。
|
||||
|
||||
|
||||
> `sockopt`: [SockoptObject](#sockoptobject)
|
||||
|
||||
透明代理相关的具体配置。
|
||||
|
@ -577,20 +588,25 @@ OCSP 装订更新,与证书热重载的时间间隔。 单位:秒。默认
|
|||
> "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"<br>
|
||||
> "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
|
||||
|
||||
Xray-core v1.8.6 新增功能:<br>
|
||||
`"UseIPv6v4"` | `"UseIPv4v6"`<br>
|
||||
`"ForceIP"` | `"ForceIPv6v4"` | `"ForceIPv6"` | `"ForceIPv4v6"` | `"ForceIPv4"`
|
||||
|
||||
在之前的版本中,当 Xray 尝试使用域名建立系统连接时,域名的解析由系统完成,不受 Xray
|
||||
控制。这导致了在 [非标准 Linux 环境中无法解析域名](https://github.com/v2ray/v2ray-core/issues/1909) 等问题。为此,Xray 1.3.1 为 Sockopt 引入了 Freedom
|
||||
中的 domainStrategy,解决了此问题。
|
||||
|
||||
在目标地址为域名时, 配置相应的值, SystemDialer 的行为模式如下:
|
||||
默认值 `"AsIs"`。
|
||||
|
||||
- `"AsIs"`: 通过系统 DNS 服务器解析获取 IP, 向此域名发出连接。
|
||||
- `"UseIP"`、`"UseIPv4"` 和 `"UseIPv6"`: 使用[内置 DNS 服务器](./dns.md)解析获取 IP 后, 直接向此 IP 发出连接。
|
||||
当目标地址为域名时,配置相应的值,Freedom 的行为模式如下:
|
||||
|
||||
默认值为 `"AsIs"`。
|
||||
- 当使用 `"AsIs"` 时,Xray将直接使用系统栈发起连接,优先级与选择IP取决于系统设置。
|
||||
- 当填写其他值时,将使用 Xray-core [内置 DNS 服务器](../dns.md) 服务器进行解析。若不存在DNSObject,则使用系统DNS。若有多个符合条件的IP地址时,核心会随机选择一个IP作为目标IP。
|
||||
- `"IPv4"` 代表尝试仅使用IPv4进行连接,`"IPv4v6"` 代表尝试使用IPv4或IPv6连接,但对于双栈域名,尽量使用IPv4。(v4v6调换后同理,不再赘述)
|
||||
- 当在内置DNS设置了 `"queryStrategy"` 后,实际行为将会与这个选项取并,只有都被包含的IP类型才会被解析,如 `"queryStrategy": "UseIPv4"` `"domainStrategy": "UseIP"`,实际上等同于 `"domainStrategy": "UseIPv4"`。
|
||||
- 当使用 `"Use"` 开头的选项时,若解析结果不符合要求(如,域名只有IPv4解析结果但使用了UseIPv6),则会回落回AsIs。
|
||||
- 当使用 `"Force"` 开头的选项时,若解析结果不符合要求,则该连接会无法建立。
|
||||
|
||||
::: tip TIP
|
||||
当使用 `"UseIP"`、`"ForceIP"` 模式时,并且 [出站连接配置](../outbound.md#outboundobject) 中指定了 `sendThrough` 时,Freedom 会根据 `sendThrough` 的值自动判断所需的 IP 类型,IPv4 或 IPv6。若手动指定了单种IP类型(如UseIPv4),但与 `sendThrough` 指定的本地地址不匹配,将会导致连接失败。
|
||||
:::
|
||||
|
||||
::: danger
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ gRPC(HTTP/2)内置多路复用,不建议使用 gRPC 与 HTTP/2 时启用 m
|
|||
|
||||
```json
|
||||
{
|
||||
"authority": "grpc.example.com",
|
||||
"serviceName": "name",
|
||||
"multiMode": false,
|
||||
"user_agent": "custom user agent",
|
||||
|
@ -45,13 +46,17 @@ gRPC(HTTP/2)内置多路复用,不建议使用 gRPC 与 HTTP/2 时启用 m
|
|||
}
|
||||
```
|
||||
|
||||
> `authority`: string
|
||||
|
||||
一个字符串,可以当 Host 来用,实现一些其它用途。
|
||||
|
||||
> `serviceName`: string
|
||||
|
||||
一个字符串,指定服务名称,**类似于** HTTP/2 中的 Path。
|
||||
客户端会使用此名称进行通信,服务端会验证服务名称是否匹配。
|
||||
|
||||
::: tip
|
||||
当 `serviceName` 起始为斜杠时可以自定义 path。<br>
|
||||
当 `serviceName` 起始为斜杠时可以自定义 path,至少要两个斜杠。<br>
|
||||
例如在服务端填写 `"serviceName": "/my/sample/path1|path2"`,客户端可填写 `"serviceName": "/my/sample/path1"` 或 `"/my/sample/path2"`。
|
||||
:::
|
||||
|
||||
|
|
49
docs/config/transports/httpupgrade.md
Normal file
49
docs/config/transports/httpupgrade.md
Normal file
|
@ -0,0 +1,49 @@
|
|||
# HTTPUpgrade
|
||||
|
||||
一个实现了类似于 WebSocket 进行 HTTP 1.1 升级请求和响应的协议,这使得它可以像 WebSocket 一样可以被CDN或者Nginx进行反代,但无需实现 WebSocket 协议的其他部分,所以具有更高的效率。
|
||||
其设计不推荐单独使用,而是和TLS等安全协议一起工作。
|
||||
|
||||
## HttpUpgradeObject
|
||||
|
||||
`HttpUpgradeObject` 对应传输配置的 `httpupgradeSettings` 项。
|
||||
|
||||
```json
|
||||
{
|
||||
"acceptProxyProtocol": false,
|
||||
"path": "/",
|
||||
"host": "xray.com"
|
||||
"headers": {
|
||||
"key": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `acceptProxyProtocol`: true | false
|
||||
|
||||
仅用于 inbound,指示是否接收 PROXY protocol。
|
||||
|
||||
[PROXY protocol](https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) 专用于传递请求的真实来源 IP 和端口,**若你不了解它,请先忽略该项**。
|
||||
|
||||
常见的反代软件(如 HAProxy、Nginx)都可以配置发送它,VLESS fallbacks xver 也可以发送它。
|
||||
|
||||
填写 `true` 时,最底层 TCP 连接建立后,请求方必须先发送 PROXY protocol v1 或 v2,否则连接会被关闭。
|
||||
|
||||
> `path`: string
|
||||
|
||||
HTTPUpgrade 所使用的 HTTP 协议路径,默认值为 `"/"`。
|
||||
|
||||
如果客户端路径中包含 `ed` 参数(如 ```/mypath?ed=2560```),将会启用 `Early Data` 以降低延迟,其值为首包长度阈值。如果首包长度超过此值,就不会启用 `Early Data`。建议的值为2560。
|
||||
|
||||
> `host`: string
|
||||
|
||||
HTTPUpgrade 的HTTP请求中所发送的host,默认值为空。若服务端值为空时,不验证客户端发送来的host值。
|
||||
|
||||
当在服务端指定该值,或在 ```headers``` 中指定host,将会校验与客户端请求host是否一致。
|
||||
|
||||
客户端选择发送的host优先级 ```host``` > ```headers``` > ```address```
|
||||
|
||||
> `headers`: map \{string: string\}
|
||||
|
||||
自定义 HTTP 头,一个键值对,每个键表示一个 HTTP 头的名称,对应的值是字符串。
|
||||
|
||||
默认值为空。
|
|
@ -16,8 +16,9 @@ Websocket 会识别 HTTP 请求的 X-Forwarded-For 头来覆写流量的源地
|
|||
{
|
||||
"acceptProxyProtocol": false,
|
||||
"path": "/",
|
||||
"host": "xray.com"
|
||||
"headers": {
|
||||
"Host": "xray.com"
|
||||
"host": "xray.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -36,11 +37,15 @@ Websocket 会识别 HTTP 请求的 X-Forwarded-For 头来覆写流量的源地
|
|||
|
||||
WebSocket 所使用的 HTTP 协议路径,默认值为 `"/"`。
|
||||
|
||||
如果路径中包含 `ed` 参数,将会启用 `Early Data` 以降低延迟,其值为首包长度阈值。如果首包长度超过此值,就不会启用 `Early Data`。建议的值为 2048。
|
||||
如果客户端路径中包含 `ed` 参数(如 ```/mypath?ed=2560```),将会启用 `Early Data` 以降低延迟,在升级的同时使用 `Sec-WebSocket-Protocol` 头承载首包数据,其值为首包长度阈值。如果首包长度超过此值,就不会启用 `Early Data`。推荐值为 2560,最大值为8192,过大的值可能导致部分兼容问题,如果遇到兼容性问题,可以尝试调低阈值。
|
||||
|
||||
::: warning
|
||||
`Early Data` 使用 `Sec-WebSocket-Protocol` 头承载数据。如果你遇到兼容性问题,可以尝试调低阈值。
|
||||
:::
|
||||
> `host`: string
|
||||
|
||||
WebSocket 的HTTP请求中所发送的host,默认值为空。若服务端值为空时,不验证客户端发送来的host值。
|
||||
|
||||
当在服务端指定该值,或在 ```headers``` 中指定host,将会校验与客户端请求host是否一致。
|
||||
|
||||
客户端选择发送的host优先级 ```host``` > ```headers``` > ```address```
|
||||
|
||||
> `headers`: map \{string: string\}
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
### 版本控制
|
||||
|
||||
project X 的代码被托管在 github 上:
|
||||
Project X 的代码被托管在 github 上:
|
||||
|
||||
- xray 核心 [xray-core](https://github.com/XTLS/Xray-core)
|
||||
- Xray 核心 [Xray-core](https://github.com/XTLS/Xray-core)
|
||||
- 安装脚本 [Xray-install](https://github.com/XTLS/Xray-install)
|
||||
- 配置模板 [Xray-examples](https://github.com/XTLS/Xray-examples)
|
||||
- xray 文档 [Xray-docs-next](https://github.com/XTLS/Xray-docs-next)
|
||||
- Xray 文档 [Xray-docs-next](https://github.com/XTLS/Xray-docs-next)
|
||||
|
||||
您可以使用 [Git](https://git-scm.com/) 来获取代码。
|
||||
|
||||
|
@ -32,7 +32,7 @@ project X 的代码被托管在 github 上:
|
|||
### 引用其它项目
|
||||
|
||||
- Golang
|
||||
- 产品代码建议使用 Golang 标准库和 [golang.org/x/](https://pkg.go.dev/search?q=golang.org%2Fx) 下的库;
|
||||
- 产品代码建议使用 Golang 标准库和 [golang.org/x/](https://pkg.go.dev/search?limit=25&m=package&q=golang.org%2Fx) 下的库;
|
||||
- 如需引用其它项目,请事先创建 issue 讨论;
|
||||
- 其它
|
||||
- 不违反双方的协议,且对项目有帮助的工具,都可以使用。
|
||||
|
@ -56,17 +56,17 @@ project X 的代码被托管在 github 上:
|
|||
|
||||
### Pull Request
|
||||
|
||||
- 提交 PR 之前,请先运行 `git pull https://github.com/xray/xray-core.git` 以确保 merge 可顺利进行;
|
||||
- 提交 PR 之前,请先运行 `git pull https://github.com/XTLS/Xray-core.git` 以确保 merge 可顺利进行;
|
||||
- 一个 PR 只做一件事,如有对多个 bug 的修复,请对每一个 bug 提交一个 PR;
|
||||
- 由于 Golang 的特殊需求(Package path),Go 项目的 PR 流程和其它项目有所不同,建议流程如下:
|
||||
1. 先 Fork 本项目,创建你自己的 `github.com/<your_name>/Xray-core.git` 仓库;
|
||||
2. 克隆你自己的 Xray 仓库到本地:`git clone https://github.com/<your_name>/Xray-core.git`;
|
||||
3. 基于 `main` 分支创建新的分支,例如 `git branch issue24 main`;
|
||||
4. 在新创建的分支上作修改并提交修改(commit);
|
||||
5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 `main` 分支,运行 `git pull https://github.com/xray/xray-core.git` 拉取最新的远端代码;
|
||||
5. 在推送(push)修改完成的分支到自己的仓库前,先切换到 `main` 分支,运行 `git pull https://github.com/XTLS/Xray-core.git` 拉取最新的远端代码;
|
||||
6. 如果上一步拉取得到了新的远端代码,则切换到之前自己创建的分支,运行 `git rebase main` 执行分支合并操作。如遇到文件冲突,则需要解决冲突;
|
||||
7. 上一步处理完毕后,就可以把自己创建的分支推送到自己的仓库:`git push -u origin your-branch`
|
||||
8. 最后,把自己仓库的新推送的分支往 `xtls/Xray-core` 的 `main` 分支发 PR 即可;
|
||||
8. 最后,把自己仓库的新推送的分支往 `XTLS/Xray-core` 的 `main` 分支发 PR 即可;
|
||||
9. 请在 PR 的标题和正文中,完整表述此次 PR 解决的问题 / 新增的功能 / 代码所做的修改的用意等;
|
||||
10. 耐心等待开发者的回应。
|
||||
|
||||
|
|
|
@ -42,18 +42,24 @@ Use "xray help <command>" for more information about a command.
|
|||
```
|
||||
Run Xray with config, the default command.
|
||||
|
||||
The -config=file, -c=file flags set the config files for
|
||||
The -config=file, -c=file flags set the config files for
|
||||
Xray. Multiple assign is accepted.
|
||||
|
||||
The -confdir=dir flag sets a dir with multiple json config
|
||||
|
||||
The -format=json flag sets the format of config files.
|
||||
The -format=json flag sets the format of config files.
|
||||
Default "auto".
|
||||
|
||||
The -test flag tells Xray to test config files only,
|
||||
without launching the server
|
||||
```
|
||||
The -test flag tells Xray to test config files only,
|
||||
without launching the server.
|
||||
|
||||
The -dump flag tells Xray to print the merged config.
|
||||
```
|
||||
`-config=` / `-c=` 用于指定使用的配置文件的位置,支持多文件配置。
|
||||
`-confdir=` 用于指定一个包含多个配置文件的文件夹。
|
||||
`-format=` 用于指定使用的配置文件的格式。
|
||||
`-test` 用于测试配置文件的合法性。
|
||||
`-dump` 用于显示多文件配置文件合并之后的效果。
|
||||
::: tip
|
||||
配置文件除了默认的 JSON 格式外,也可以使用 TOML 和 YAML。在不指定格式的前提下会通过文件扩展名识别。
|
||||
:::
|
||||
|
|
|
@ -8,7 +8,7 @@ Project X 的文档托管在 [GitHub](https://github.com/XTLS/Xray-docs-next)
|
|||
|
||||
您可以通过以下步骤, 提交您对文档的改动:
|
||||
|
||||
1. 从 [project X 文档仓库](https://github.com/XTLS/Xray-docs-next) 打开仓库, 点击右上角的 fork, fork 一份文档仓库的镜像到您自己的 github 仓库.
|
||||
1. 从 [Project X 文档仓库](https://github.com/XTLS/Xray-docs-next) 打开仓库, 点击右上角的 fork, fork 一份文档仓库的镜像到您自己的 github 仓库.
|
||||
|
||||
2. 使用任何您喜欢的工具, 从您克隆的仓库获得文档的克隆, 如:
|
||||
|
||||
|
@ -36,7 +36,7 @@ git checkout -b your-branch
|
|||
git push -u origin your-branch
|
||||
```
|
||||
|
||||
6. 打开 GitHub, 点击 'Pull request' 向 [project X 文档仓库](https://github.com/XTLS/Xray-docs-next) 提交 PR。
|
||||
6. 打开 GitHub, 点击 'Pull request' 向 [Project X 文档仓库](https://github.com/XTLS/Xray-docs-next) 提交 PR。
|
||||
|
||||
7. 请在 PR 的标题和正文中,概述此次 PR 新增/修改的内容等;
|
||||
|
||||
|
|
|
@ -28,6 +28,36 @@
|
|||
|
||||

|
||||
|
||||
3. 如果无法看到上述Nginx默认页面,可能是需要配置Debian系统上默认的防火墙组件Uncomplicated Firewall (UFW),以便启用 HTTP (80) 和 HTTPS (443) 端口流量。
|
||||
|
||||
a. 验证方法,输入:
|
||||
```shell
|
||||
sudo ufw status
|
||||
```
|
||||
b. 如果输出如下,表明80和433端口未开启,需要执行c步骤
|
||||
```shell
|
||||
Status: active
|
||||
To Action From
|
||||
-- ------ ----
|
||||
22/tcp ALLOW Anywhere
|
||||
22/tcp (v6) ALLOW Anywhere (v6)
|
||||
```
|
||||
c. 启用UFW的Nginx 80 和 443 端口命令
|
||||
```shell
|
||||
sudo ufw allow 'Nginx Full'
|
||||
```
|
||||
d. 输入a中命令再次验证,如果输出如下,表示Nginx流量已经被防火墙放行,这样就应该可以看到前述第2点中的Nginx默认页面。
|
||||
```shell
|
||||
Status: active
|
||||
To Action From
|
||||
-- ------ ----
|
||||
22/tcp ALLOW Anywhere
|
||||
Nginx Full ALLOW Anywhere
|
||||
22/tcp (v6) ALLOW Anywhere (v6)
|
||||
Nginx Full (v6) ALLOW Anywhere (v6)
|
||||
```
|
||||
|
||||
|
||||
## 5.3 创建一个最简单的网页
|
||||
|
||||
1. 小小白白 Linux 基础命令:
|
||||
|
@ -94,7 +124,13 @@
|
|||
</html>
|
||||
```
|
||||
|
||||
5. 修改 `nginx.conf` 并重启 `Nginx` 服务,将`80`端口的 http 访问定位到刚才建立的 `html` 页面上
|
||||
赋予其他用户读取该文件的权限
|
||||
|
||||
```shell
|
||||
chmod -R a+r .
|
||||
```
|
||||
|
||||
6. 修改 `nginx.conf` 并重启 `Nginx` 服务,将`80`端口的 http 访问定位到刚才建立的 `html` 页面上
|
||||
|
||||
1. 修改 `nginx.conf` 。
|
||||
|
||||
|
|
|
@ -74,3 +74,7 @@ Reverse proxy. You can forward server-side traffic to the client, that is, rever
|
|||
> fakedns: [FakeDnsObject](./fakedns.md)
|
||||
|
||||
FakeDNS configuration. It can be used with transparent proxy to obtain the actual domain name.
|
||||
|
||||
> metrics: [metricsObject](./metrics.md)
|
||||
|
||||
Metrics configuration. A more straightforward (and hopefully better) way to export metrics.
|
275
docs/en/config/metrics.md
Normal file
275
docs/en/config/metrics.md
Normal file
|
@ -0,0 +1,275 @@
|
|||
# Metrics
|
||||
|
||||
A more straightforward (and hopefully better) way to export metrics.
|
||||
|
||||
## Related configurations
|
||||
|
||||
It's possible to add a metrics inbound among inbounds.
|
||||
|
||||
```json
|
||||
"inbounds": [
|
||||
{
|
||||
"listen": "127.0.0.1",
|
||||
"port": 11111,
|
||||
"protocol": "dokodemo-door",
|
||||
"settings": {
|
||||
"address": "127.0.0.1"
|
||||
},
|
||||
"tag": "metrics_in"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
And add routing rules regarding the metrics inbound in the routing configuration.
|
||||
|
||||
```json
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"type": "field",
|
||||
"inboundTag": [
|
||||
"metrics_in"
|
||||
],
|
||||
"outboundTag": "metrics_out"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Then finally, enable metrics under the root object.
|
||||
|
||||
```json
|
||||
"metrics": {
|
||||
"tag": "metrics_out"
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### pprof
|
||||
|
||||
Access `http://127.0.0.1:11111/debug/pprof/` or use go tool pprof to start profiling or inspect running goroutines.
|
||||
|
||||
### expvars
|
||||
|
||||
Access `http://127.0.0.1:11111/debug/vars`
|
||||
|
||||
Variables exported include:
|
||||
* `stats` includes statistics about inbounds, outbounds and users
|
||||
* `observatory` includes observatory results
|
||||
|
||||
for example with [luci-app-xray](https://github.com/yichya/luci-app-xray) you are likely to get a result like this (standard expvar things like `cmdline` and `memstats` are omitted)
|
||||
|
||||
<details><summary>Click to expand</summary><br>
|
||||
|
||||
```json
|
||||
{
|
||||
"observatory": {
|
||||
"tcp_outbound": {
|
||||
"alive": true,
|
||||
"delay": 782,
|
||||
"outbound_tag": "tcp_outbound",
|
||||
"last_seen_time": 1648477189,
|
||||
"last_try_time": 1648477189
|
||||
},
|
||||
"udp_outbound": {
|
||||
"alive": true,
|
||||
"delay": 779,
|
||||
"outbound_tag": "udp_outbound",
|
||||
"last_seen_time": 1648477191,
|
||||
"last_try_time": 1648477191
|
||||
}
|
||||
},
|
||||
"stats": {
|
||||
"inbound": {
|
||||
"api": {
|
||||
"downlink": 0,
|
||||
"uplink": 0
|
||||
},
|
||||
"dns_server_inbound_5300": {
|
||||
"downlink": 14286,
|
||||
"uplink": 5857
|
||||
},
|
||||
"http_inbound": {
|
||||
"downlink": 74460,
|
||||
"uplink": 10231
|
||||
},
|
||||
"https_inbound": {
|
||||
"downlink": 0,
|
||||
"uplink": 0
|
||||
},
|
||||
"metrics": {
|
||||
"downlink": 6327,
|
||||
"uplink": 1347
|
||||
},
|
||||
"socks_inbound": {
|
||||
"downlink": 19925615,
|
||||
"uplink": 5512
|
||||
},
|
||||
"tproxy_tcp_inbound": {
|
||||
"downlink": 4739161,
|
||||
"uplink": 1568869
|
||||
},
|
||||
"tproxy_udp_inbound": {
|
||||
"downlink": 0,
|
||||
"uplink": 2608142
|
||||
}
|
||||
},
|
||||
"outbound": {
|
||||
"blackhole_outbound": {
|
||||
"downlink": 0,
|
||||
"uplink": 0
|
||||
},
|
||||
"direct": {
|
||||
"downlink": 97714548,
|
||||
"uplink": 3234617
|
||||
},
|
||||
"dns_server_outbound": {
|
||||
"downlink": 7116,
|
||||
"uplink": 2229
|
||||
},
|
||||
"manual_tproxy_outbound_tcp_1": {
|
||||
"downlink": 0,
|
||||
"uplink": 0
|
||||
},
|
||||
"manual_tproxy_outbound_udp_1": {
|
||||
"downlink": 0,
|
||||
"uplink": 0
|
||||
},
|
||||
"tcp_outbound": {
|
||||
"downlink": 23873238,
|
||||
"uplink": 1049595
|
||||
},
|
||||
"udp_outbound": {
|
||||
"downlink": 639282,
|
||||
"uplink": 74634
|
||||
}
|
||||
},
|
||||
"user": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
To get a better view of these numbers, [Netdata](https://github.com/netdata/netdata) (with python.d plugin) is a great option:
|
||||
|
||||
1. Edit related configuration file (`sudo /etc/netdata/edit-config python.d/go_expvar.conf`)
|
||||
2. Take the following configuration file as an example:
|
||||
|
||||
<details><summary>Click to expand</summary><br>
|
||||
|
||||
```
|
||||
xray:
|
||||
name: 'xray'
|
||||
update_every: 2
|
||||
url: 'http://127.0.0.1:11111/debug/vars'
|
||||
collect_memstats: false
|
||||
extra_charts:
|
||||
- id: 'inbounds'
|
||||
options:
|
||||
name: 'inbounds'
|
||||
title: 'Xray System Inbounds'
|
||||
units: bytes
|
||||
family: xray
|
||||
context: xray.inbounds
|
||||
chart_type: line
|
||||
lines:
|
||||
- expvar_key: stats.inbound.tproxy_tcp_inbound.downlink
|
||||
id: 'tcp.downlink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.tproxy_udp_inbound.downlink
|
||||
id: 'udp.downlink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.http_inbound.downlink
|
||||
id: 'http.downlink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.https_inbound.downlink
|
||||
id: 'https.downlink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.socks_inbound.downlink
|
||||
id: 'socks.downlink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.tproxy_tcp_inbound.uplink
|
||||
id: 'tcp.uplink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.tproxy_udp_inbound.uplink
|
||||
id: 'udp.uplink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.http_inbound.uplink
|
||||
id: 'http.uplink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.https_inbound.uplink
|
||||
id: 'https.uplink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.inbound.socks_inbound.uplink
|
||||
id: 'socks.uplink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- id: 'outbounds'
|
||||
options:
|
||||
name: 'outbounds'
|
||||
title: 'Xray System Outbounds'
|
||||
units: bytes
|
||||
family: xray
|
||||
context: xray.outbounds
|
||||
chart_type: line
|
||||
lines:
|
||||
- expvar_key: stats.outbound.tcp_outbound.downlink
|
||||
id: 'tcp.downlink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.outbound.udp_outbound.downlink
|
||||
id: 'udp.downlink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.outbound.direct.downlink
|
||||
id: 'direct.downlink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.outbound.tcp_outbound.uplink
|
||||
id: 'tcp.uplink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.outbound.udp_outbound.uplink
|
||||
id: 'udp.uplink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- expvar_key: stats.outbound.direct.uplink
|
||||
id: 'direct.uplink'
|
||||
algorithm: incremental
|
||||
expvar_type: int
|
||||
- id: 'observatory'
|
||||
options:
|
||||
name: 'observatory'
|
||||
title: 'Xray Observatory Metrics'
|
||||
units: milliseconds
|
||||
family: xray
|
||||
context: xray.observatory
|
||||
chart_type: line
|
||||
lines:
|
||||
- expvar_key: observatory.tcp_outbound.delay
|
||||
id: tcp
|
||||
expvar_type: int
|
||||
- expvar_key: observatory.udp_outbound.delay
|
||||
id: udp
|
||||
expvar_type: int
|
||||
```
|
||||
</details>
|
||||
|
||||
And you will get a nice plot like this:
|
||||
|
||||

|
||||
|
||||
### Additional
|
||||
Maybe reusing the empty object `stats` in config file is better than adding `metrics` here?
|
||||
|
||||
**Edit:** removed prometheus related things and added usage about expvars
|
|
@ -13,7 +13,8 @@ Freedom is an outbound protocol that can be used to send (normal) TCP or UDP dat
|
|||
"packets": "tlshello",
|
||||
"length": "100-200",
|
||||
"interval": "10-20" // ms
|
||||
}
|
||||
},
|
||||
"proxyProtocol": 0
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -55,3 +56,7 @@ A key-value map used to control TCP fragmentation,under some circumstances it
|
|||
`"length"`: length to make the cut
|
||||
|
||||
`"interval"`: time between fragments(ms)
|
||||
|
||||
> `proxyProtocol`: number
|
||||
|
||||
The value of `proxyProtocol` represents the PROXY Protocol version. default value is `0`.
|
57
docs/en/config/outbounds/loopback.md
Normal file
57
docs/en/config/outbounds/loopback.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Loopback
|
||||
|
||||
Loopback is an outbound protocol. It can send traffics through corresponding outbound to routing inbound, thus rerouting traffics to other routing rules without leaving Xray-core.
|
||||
|
||||
## OutboundConfigurationObject
|
||||
|
||||
```json
|
||||
{
|
||||
"inboundTag": "TagUseAsInbound"
|
||||
}
|
||||
```
|
||||
|
||||
> `inboundTag`: string
|
||||
|
||||
Use as an inbound tag for routing.
|
||||
|
||||
This tag can be used as `inboundTag` in routing rules, all traffics going through this outbound can be rerouted with routing rules with corresponding inbound tag.
|
||||
|
||||
### How to use?
|
||||
|
||||
If you need to do some more detailed routing for traffics that have been routed by routing rules, like splitting routed traffics to TCP traffics and UDP traffics and send them to different outbounds, this can be done with `loopback` outbound.
|
||||
|
||||
``` jsonc
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "loopback",
|
||||
"tag": "need-to-split",
|
||||
"settings": {
|
||||
"tag": "traffic-input" // This tag will be used as the inboundTag inside the RuleObject
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "tcp-output",
|
||||
// protocol, settings, streamSettings etc.
|
||||
},
|
||||
{
|
||||
"tag": "udp-output",
|
||||
// protocol, settings, streamSettings etc.
|
||||
}
|
||||
],
|
||||
"routing": {
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": ["traffic-input"], // tag set in the loopback outbound setting
|
||||
"network": "tcp",
|
||||
"outboundTag": "tcp-output"
|
||||
},
|
||||
{
|
||||
"inboundTag": ["traffic-input"], // tag set in the loopback outbound
|
||||
"network": "udp",
|
||||
"outboundTag": "udp-output"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
|
@ -25,7 +25,8 @@ The `TransportObject` corresponds to the `transport` item in the configuration f
|
|||
"httpSettings": {},
|
||||
"quicSettings": {},
|
||||
"dsSettings": {},
|
||||
"grpcSettings": {}
|
||||
"grpcSettings": {},
|
||||
"httpupgradeSettings": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -54,6 +55,10 @@ Configuration for QUIC connections.
|
|||
|
||||
Configuration for gRPC connections.
|
||||
|
||||
> `httpupgradeSettings`: [HttpUpgradeObject](./transports/httpupgrade.md)
|
||||
|
||||
Configuration for HTTPUpgrade connections.
|
||||
|
||||
> `dsSettings`: [DomainSocketObject](./transports/domainsocket.md)
|
||||
|
||||
Configuration for Domain Socket connections.
|
||||
|
@ -74,6 +79,7 @@ Configuration for Domain Socket connections.
|
|||
"quicSettings": {},
|
||||
"dsSettings": {},
|
||||
"grpcSettings": {},
|
||||
"httpupgradeSettings": {},
|
||||
"sockopt": {
|
||||
"mark": 0,
|
||||
"tcpFastOpen": false,
|
||||
|
@ -86,16 +92,16 @@ Configuration for Domain Socket connections.
|
|||
}
|
||||
```
|
||||
|
||||
> `network`: "tcp" | "kcp" | "ws" | "http" | "domainsocket" | "quic" | "grpc"
|
||||
> `network`: "tcp" | "kcp" | "ws" | "http" | "quic" | "grpc" | "httpupgrade"
|
||||
|
||||
The type of transport used by the connection's data stream, with a default value of `"tcp"`.
|
||||
|
||||
> `security`: "none" | "tls" | "xtls"
|
||||
> `security`: "none" | "tls" | "reality"
|
||||
|
||||
Whether to enable transport layer encryption, with supported options:
|
||||
|
||||
- `"none"` means no encryption (default value).
|
||||
- `"tls"` means using [TLS](https://en.wikipedia.org/wiki/base/transport_Layer_Security).
|
||||
- `"tls"` means using [TLS](https://en.wikipedia.org/wiki/transport_Layer_Security).
|
||||
- `"xtls"` means using [XTLS](./features/xtls.md). <Badge text="Deprecated" type="warning"/>
|
||||
|
||||
> `tlsSettings`: [TLSObject](#tlsobject)
|
||||
|
@ -138,9 +144,13 @@ The gRPC configuration for the current connection, only valid when gRPC is used
|
|||
|
||||
The Domain socket configuration for the current connection, only valid when Domain socket is used for this connection. The configuration is the same as the global configuration above.
|
||||
|
||||
> `httpupgradeSettings`: [HttpUpgradeObject](./transports/httpupgrade.md)
|
||||
|
||||
Configuration of the current HTTPUpragde connection. Valid only when HTTPUpgrade is used by this connection. The configuration schema is the exact same as the global schema.
|
||||
|
||||
> `sockopt`: [SockoptObject](./chat#sockoptobject)
|
||||
|
||||
Specific configuration for transparent proxying.
|
||||
Specific configuration for transparent proxies.
|
||||
|
||||
### TLSObject
|
||||
|
||||
|
|
35
docs/en/config/transports/httpupgrade.md
Normal file
35
docs/en/config/transports/httpupgrade.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
# HttpUpgrade
|
||||
|
||||
A WebSocket-like transport protocol implementing the HTTP/1.1 upgrade and response, allowing it to be reverse proxied by web servers or CDNs just like WebSocket, but without the need to implement the remaining portions of the WebSocket protocol, yielding better performance.
|
||||
|
||||
Standalone usage is not recommended, but rather in conjunction with other security protocols like TLS.
|
||||
|
||||
## HttpUpgradeObject
|
||||
|
||||
The `HttpUpgradeObject` corresponds to the `httpupgradeSettings` section under transport configurations.
|
||||
|
||||
```json
|
||||
{
|
||||
"acceptProxyProtocol": false,
|
||||
"path": "/",
|
||||
"host": "xray.com"
|
||||
}
|
||||
```
|
||||
|
||||
> `acceptProxyProtocol`: true | false
|
||||
|
||||
For inbounds only. Specifies whether to accept the PROXY protocol.
|
||||
|
||||
The [PROXY protocol](https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) is used to pass the real IP address and port of a connection along. **Ignore it if you have no knowledge regarding this**.
|
||||
|
||||
Common reverse proxies (e.g. HAProxy, NGINX) and VLESS fallbacks xver can be configured for its inclusion.
|
||||
|
||||
When `true`, the downstream must first send PROXY protocol version 1 or 2 after establishing the underlying TCP connection, or the connection will be closed.
|
||||
|
||||
> `path`: string
|
||||
|
||||
HTTP path used by the HTTPUpgrade connection. Defaults to `"/"`.
|
||||
|
||||
> `host`: string
|
||||
|
||||
HTTP Host sent by the HTTPUpgrade connection. Empty by default.
|
|
@ -14,7 +14,7 @@ Complete tutorial on configuring transparent proxy (TProxy) based on Xray.
|
|||
|
||||
Xray-based TProxy Transparent Proxy (IPv4 and IPv6) Configuration Tutorial
|
||||
|
||||
[Nginx_TLS Tunnel Hidden Fingerprint](./Nginx_TLS_tunnel.md) by <img src="https://avatars.githubusercontent.com/u/110686480?s=32" width="32" height="32" alt="a"/> [@SQLimit](https://github.com/SQLimit)
|
||||
[Nginx_TLS Tunnel Hidden Fingerprint](./nginx_or_haproxy_tls_tunnel.md) by <img src="https://avatars.githubusercontent.com/u/110686480?s=32" width="32" height="32" alt="a"/> [@SQLimit](https://github.com/SQLimit)
|
||||
|
||||
Use Nginx_TLS tunnel on both ends to hide the fingerprint.
|
||||
|
||||
|
|
715
docs/en/document/level-2/nginx_or_haproxy_tls_tunnel.md
Normal file
715
docs/en/document/level-2/nginx_or_haproxy_tls_tunnel.md
Normal file
|
@ -0,0 +1,715 @@
|
|||
---
|
||||
title: Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹
|
||||
---
|
||||
|
||||
Nginx 或 Haproxy 实现的 HTTPS 隧道、HTTP/2 over HTTPS 隧道、WebSocket over HTTP/2 over HTTPS 隧道、gRPC over HTTP/2 over HTTPS 隧道以及自签证书双端认证的 gRPC over HTTP/2 over HTTPS 隧道
|
||||
|
||||
# 客户端服务端 Nginx 构建 HTPPS 隧道隐藏指纹
|
||||
|
||||
网路结构:
|
||||
|
||||
xray_client ---tcp--- nginx_client ---HTTPS--- nginx_sever ---tcp--- xray_server
|
||||
|
||||
## 编译 nginx --with-stream
|
||||
|
||||
在客户端及服务端均编译
|
||||
|
||||
`curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz`
|
||||
|
||||
`tar -zxvf nginx-1.22.1.tar.gz`
|
||||
|
||||
`cd nginx-1.22.1`
|
||||
|
||||
`apt install gcc make` //编译依赖 gcc 以及 make
|
||||
|
||||
`./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module` //此步需要依赖一些库,根据报错安装相应 lib
|
||||
|
||||
`make && make install`
|
||||
|
||||
编译之后 nginx 文件夹位于 `/usr/local/nginx`
|
||||
|
||||
## 配置 nginx
|
||||
|
||||
编辑 nginx 配置文件 nginx.conf
|
||||
|
||||
`vim /usr/local/nginx/conf/nginx.conf`
|
||||
|
||||
服务端加入如下配置
|
||||
|
||||
服务器申请证书不再赘述,参考[白话文](https://xtls.github.io/document/level-0/ch06-certificates.html)
|
||||
|
||||
```
|
||||
stream {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
ssl_protocols TLSv1.3;
|
||||
ssl_certificate /path/to/cert/domain.crt; # crt 文件位置
|
||||
ssl_certificate_key /path/to/cert/domain.key; # key 文件位置
|
||||
proxy_pass unix:/dev/shm/vless.sock; # 使用 domain socket
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
::: warning 注意
|
||||
|
||||
stream 部分与 http 模块并列,客户端可删除 http 部分,服务端可删除或搭建网页伪装回落
|
||||
:::
|
||||
|
||||
客户端加入如下配置
|
||||
|
||||
```
|
||||
stream {
|
||||
server {
|
||||
listen 6666;
|
||||
listen [::]:6666;
|
||||
proxy_ssl on;
|
||||
proxy_ssl_protocols TLSv1.3;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_name yourdomain.domain; # 服务器域名
|
||||
proxy_pass ip:443; # 服务器 ip 形如 proxy_pass 6.6.6.6:443; 或 proxy_pass [2401:0:0::1]:443;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在 `/etc/systemd/system` 文件夹中创建 `nginx.service` 文件
|
||||
|
||||
`vim /etc/systemd/system/nginx.service`
|
||||
|
||||
写入如下
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=The NGINX HTTP and reverse proxy server
|
||||
After=syslog.target network-online.target remote-fs.target nss-lookup.target
|
||||
After=xray.service
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStartPre=/usr/local/nginx/sbin/nginx -t
|
||||
ExecStart=/usr/local/nginx/sbin/nginx
|
||||
ExecReload=/usr/local/nginx/sbin/nginx -s reload
|
||||
ExecStop=/bin/kill -s QUIT $MAINPID
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
加入开机自启
|
||||
|
||||
`systemctl enable nginx`
|
||||
|
||||
## xray 配置
|
||||
|
||||
服务端 xray 配置
|
||||
|
||||
```
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "none"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"listen": "/dev/shm/vless.sock,0666",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "uuid"
|
||||
}
|
||||
],
|
||||
"decryption": "none"
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "tcp"
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
客户端 xray 配置,此处以旁路由透明代理为例
|
||||
|
||||
```
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "none"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
"1.1.1.1",
|
||||
{
|
||||
"address": "119.29.29.29",
|
||||
"domains": [
|
||||
"geosite:cn"
|
||||
],
|
||||
"expectIP": [
|
||||
"geoip:cn"
|
||||
]
|
||||
}
|
||||
],
|
||||
"disableFallback": true,
|
||||
"disableFallbackIfMatch": true
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"tag": "tproxy-in",
|
||||
"port": 12345,
|
||||
"protocol": "dokodemo-door",
|
||||
"settings": {
|
||||
"network": "tcp,udp",
|
||||
"followRedirect": true
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls"
|
||||
]
|
||||
},
|
||||
"streamSettings": {
|
||||
"sockopt": {
|
||||
"tproxy": "tproxy",
|
||||
"mark": 255
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "http",
|
||||
"port": 10808,
|
||||
"listen": "127.0.0.1",
|
||||
"protocol": "http",
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"tag": "nginxtls",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"vnext": [
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"port": 6666,
|
||||
"users": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"encryption": "none"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"streamSettings": {
|
||||
"sockopt": {
|
||||
"mark": 255
|
||||
},
|
||||
"network": "tcp"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "direct",
|
||||
"protocol": "freedom",
|
||||
"streamSettings": {
|
||||
"sockopt": {
|
||||
"mark": 255
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "block",
|
||||
"protocol": "blackhole",
|
||||
"settings": {
|
||||
"response": {
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"routing": {
|
||||
"domainMatcher": "mph",
|
||||
"domainStrategy": "AsIs",
|
||||
"rules": [
|
||||
{
|
||||
"type": "field",
|
||||
"domain": [
|
||||
"geosite:category-ads-all"
|
||||
],
|
||||
"outboundTag": "block"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"port": 123,
|
||||
"network": "udp",
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"ip": [
|
||||
"1.1.1.1"
|
||||
],
|
||||
"outboundTag": "proxy"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"domain": [
|
||||
"geosite:cn"
|
||||
],
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"protocol": [
|
||||
"bittorrent"
|
||||
],
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"ip": [
|
||||
"geoip:private"
|
||||
],
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"inboundTag": [
|
||||
"tproxy-in"
|
||||
],
|
||||
"outboundTag": "nginxtls"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果使用透明代理需要在 iptables 或 ip6tables 配置中加入
|
||||
|
||||
```
|
||||
# 设置策略路由 v4
|
||||
ip rule add fwmark 1 table 100
|
||||
ip route add local 0.0.0.0/0 dev lo table 100
|
||||
|
||||
# 设置策略路由 v6
|
||||
ip -6 rule add fwmark 1 table 106
|
||||
ip -6 route add local ::/0 dev lo table 106
|
||||
|
||||
# VPS IP 直连
|
||||
iptables -t mangle -A XRAY_MASK -d VSP_IPv4/32 -j RETURN
|
||||
ip6tables -t mangle -A XRAY6_MASK -d VPS_IPv6/128 -j RETURN
|
||||
```
|
||||
|
||||
## 客户端及服务端启动服务
|
||||
|
||||
`systemctl restart xray`
|
||||
|
||||
`systemctl restart nginx`
|
||||
|
||||
## 结束
|
||||
|
||||
# 双端 Haproxy 构建 HTPPS 隧道隐藏指纹
|
||||
|
||||
安装 Haproxy
|
||||
|
||||
`pacman -Su haproxy` 或 `apt install haproxy`
|
||||
|
||||
Haproxy 处理 ssl 需要 openssl 支持,检查 openssl 版本,必要时安装或更新
|
||||
|
||||
## HTTPS 隧道
|
||||
|
||||
前述 Nginx HTTPS 隧道 Hproxy 同样可以简单做到
|
||||
|
||||
网路结构:
|
||||
|
||||
xray_client ---tcp--- haproxy_client ---HTTPS--- haproxy_sever ---tcp--- xray_server
|
||||
|
||||
### haproxy_client 配置 (运行前去掉注释)
|
||||
|
||||
```
|
||||
global
|
||||
log /dev/log local0 alert
|
||||
log /dev/log local1 alert
|
||||
stats socket /dev/shm/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user root
|
||||
group root
|
||||
daemon
|
||||
|
||||
# 隧道强制使用 TLS 1.3
|
||||
ssl-default-server-options ssl-min-ver TLSv1.3
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode tcp
|
||||
timeout connect 5s
|
||||
timeout client 300s
|
||||
timeout server 300s
|
||||
|
||||
frontend xray
|
||||
bind 127.0.0.1:6666 # 监听本机 6666 端口
|
||||
default_backend tunnel
|
||||
|
||||
backend tunnel
|
||||
server tunnel www.example.com:443 ssl verify none sni req.hdr(host) alpn h2,http/1.1
|
||||
# 域名或 IP 均可以,若填域名建议在 hosts 中指定 IP 降低解析时间;alpn 与服务器协商,服务器端为 alpn h2,http1.1 时,客户端指定为 h2 则隧道为 HTTP2 方式连接,指定为 http1.1 为 HTTP 方式,双端均写优先 h2
|
||||
```
|
||||
|
||||
### haproxy_server 配置 (运行前去掉注释)
|
||||
|
||||
```
|
||||
global
|
||||
log /dev/log local0 alert
|
||||
log /dev/log local1 alert
|
||||
stats socket /dev/shm/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user root
|
||||
group root
|
||||
daemon
|
||||
|
||||
# 指定安全套件并指定 ssl 版本最低 1.2 增加真实性
|
||||
ssl-default-bind-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256
|
||||
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
|
||||
ssl-default-bind-options ssl-min-ver TLSv1.2
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode tcp
|
||||
timeout connect 5s
|
||||
timeout client 300s
|
||||
timeout server 300s
|
||||
|
||||
frontend tls-in
|
||||
bind :::443 ssl crt /path/to/pem alpn h2,http/1.1 # haproxy 使用 pem 进行 ssl 解密,pem 由 cat www.example.com.crt www.example.com.key > www.example.com.pem 获得
|
||||
default_backend xray
|
||||
tcp-request inspect-delay 5s
|
||||
tcp-request content accept if HTTP
|
||||
use_backend web if HTTP
|
||||
|
||||
backend xray
|
||||
server xray /dev/shm/vless.sock # 支持 abstract 格式: "abns@vless.sock" ;loopback 方式:127.0.0.1:6666
|
||||
|
||||
backend web
|
||||
server web /dev/shm/h1h2c.sock # 回落到网页
|
||||
```
|
||||
|
||||
### xray 配置
|
||||
|
||||
同上 nginx 部分:最简单的 TCP 配置,可搭配任意协议,建议使用 VLESS+TCP 无需多余加密,参考文档或其他示例
|
||||
|
||||
## WebSocket over HTTP/2
|
||||
|
||||
Haproxy 支持 HTTP/2 的 h2c 进站及出站
|
||||
|
||||
然而援引 xray 文档 HTTP/2 的说明
|
||||
|
||||
“由 HTTP/2 的建议,客户端和服务器必须同时开启 TLS 才可以正常使用这个传输方式。...... 当前版本的 HTTP/2 的传输方式并不强制要求入站(服务端)有 TLS 配置。”
|
||||
|
||||
即入站可以使用 h2c,出站并不支持 h2c。因此无法使用 xray_client ---h2c--- haproxy_client ---HTTP/2+TLS--- haproxy_sever ---h2c--- xray_server
|
||||
|
||||
但是可以通过 ws 偷个鸡,Haproxy 支持 ws over HTTP/2
|
||||
|
||||
则网络结构:xray_client ---ws--- haproxy_client ---ws over HTTP/2 over HTTPS--- haproxy_sever ---ws--- xray_server
|
||||
|
||||
### haproxy_client 配置
|
||||
|
||||
```
|
||||
global
|
||||
log /dev/log local0 alert
|
||||
log /dev/log local1 alert
|
||||
stats socket /dev/shm/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user root
|
||||
group root
|
||||
daemon
|
||||
|
||||
# 调整 HTTP/2 的性能,当遇到 HTTP/2 性能问题时都可以设置相关项,更多设置见 Haproxy 文档 tune.h2 部分 https://docs.haproxy.org/2.7/configuration.html
|
||||
tune.h2.initial-window-size 536870912 # 初始窗口大小,建议设置,默认值 65536 单位 byte,此值在突发大流量情况下需要一定加载时间,建议根据网速调整
|
||||
tune.h2.max-concurrent-streams 512 # 复用线路数,可根据情况设置,默认值 100,一般不用设置(官方不建议改动)
|
||||
|
||||
ssl-default-server-options ssl-min-ver TLSv1.3
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode http
|
||||
timeout connect 5s
|
||||
timeout client 300s
|
||||
timeout server 300s
|
||||
|
||||
frontend xray
|
||||
bind 127.0.0.1:6666
|
||||
default_backend tunnel
|
||||
|
||||
backend tunnel
|
||||
server tunnel www.example.com:443 ssl verify none sni req.hdr(host) ws h2 alpn h2
|
||||
# ws over HTTP/2
|
||||
```
|
||||
|
||||
### haproxy_server 配置
|
||||
|
||||
```
|
||||
global
|
||||
log /dev/log local0 alert
|
||||
log /dev/log local1 alert
|
||||
stats socket /dev/shm/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user root
|
||||
group root
|
||||
daemon
|
||||
|
||||
# 客户端配置即可,服务端配置也无妨
|
||||
tune.h2.initial-window-size 536870912
|
||||
tune.h2.max-concurrent-streams 512
|
||||
|
||||
ssl-default-bind-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256
|
||||
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
|
||||
ssl-default-bind-options ssl-min-ver TLSv1.2
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode http
|
||||
timeout connect 5s
|
||||
timeout client 300s
|
||||
timeout server 300s
|
||||
|
||||
frontend tls-in
|
||||
bind :::443 ssl crt /path/to/pem alpn h2,http/1.1
|
||||
use_backend xray if { ssl_fc_alpn -i h2 } { path_beg /tunnel }
|
||||
use_backend server1 if { ssl_fc_alpn -i h2 } { path_beg /path1 }
|
||||
use_backend server2 if { ssl_fc_alpn -i h2 } { path_beg /path2 }
|
||||
use_backend server3 if { ssl_fc_alpn -i h2 } { path_beg /path3 }
|
||||
default_backend web
|
||||
# haproxy 使用 http 模式可以根据 path 分流
|
||||
|
||||
backend xray
|
||||
server xray abns@vless.sock ws h1
|
||||
|
||||
backend server1
|
||||
server server1 abns@server1.sock ws h1
|
||||
|
||||
backend server2
|
||||
server server2 abns@server2.sock ws h1
|
||||
|
||||
backend server3
|
||||
server server3 abns@server3.sock ws h1
|
||||
|
||||
backend web
|
||||
server web /dev/shm/h1h2c.sock
|
||||
```
|
||||
|
||||
### xray 配置
|
||||
|
||||
简单的 websocket 配置即可,无需 TLS, 配置见 xray 文档示例,配置 "path" 可以用于服务端 haproxy 分流(客户端有分流需求同样可以通过客户端 haproxy 进行,原理类似,参考服务端的 path 分流配置)
|
||||
|
||||
## gRPC over HTTP/2
|
||||
|
||||
虽然双端的 h2c 不行,但是 gRPC 不要求必须 TLS,直接冲
|
||||
|
||||
网络结构:xray_client ---gRPC h2c--- haproxy_client ---gRPC over HTTP/2 over HTTPS--- haproxy_sever ---gRPC h2c--- xray_server
|
||||
|
||||
### haproxy_client 配置
|
||||
|
||||
```
|
||||
global
|
||||
log /dev/log local0 alert
|
||||
log /dev/log local1 alert
|
||||
stats socket /dev/shm/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user root
|
||||
group root
|
||||
daemon
|
||||
|
||||
tune.h2.initial-window-size 536870912
|
||||
tune.h2.max-concurrent-streams 512
|
||||
|
||||
ssl-default-server-options ssl-min-ver TLSv1.3
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode http
|
||||
timeout connect 5s
|
||||
timeout client 300s
|
||||
timeout server 300s
|
||||
|
||||
frontend xray
|
||||
bind 127.0.0.1:6666 proto h2 # 指定 proto h2 使用 h2c
|
||||
default_backend tunnel
|
||||
|
||||
backend tunnel
|
||||
server tunnel www.example.com:443 ssl verify none sni req.hdr(host) alpn h2
|
||||
```
|
||||
|
||||
### haproxy_server 配置
|
||||
|
||||
```
|
||||
global
|
||||
log /dev/log local0 alert
|
||||
log /dev/log local1 alert
|
||||
stats socket /dev/shm/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user root
|
||||
group root
|
||||
daemon
|
||||
|
||||
tune.h2.initial-window-size 536870912
|
||||
tune.h2.max-concurrent-streams 512
|
||||
|
||||
ssl-default-bind-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256
|
||||
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
|
||||
ssl-default-bind-options ssl-min-ver TLSv1.2
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode http
|
||||
timeout connect 5s
|
||||
timeout client 300s
|
||||
timeout server 300s
|
||||
|
||||
frontend tls-in
|
||||
bind :::443 ssl crt /path/to/pem alpn h2,http/1.1
|
||||
use_backend xray if { ssl_fc_alpn -i h2 } { path_beg /tunnel } # xray gRPC 中配置的 "serviceName" 在 harpoxy 中可以使用 path 进行分流,为方便使用 "multiMode",使用 path_beg 参数匹配路径
|
||||
use_backend server1 if { ssl_fc_alpn -i h2 } { path_beg /path1 }
|
||||
use_backend server2 if { ssl_fc_alpn -i h2 } { path_beg /path2 }
|
||||
use_backend server3 if { ssl_fc_alpn -i h2 } { path_beg /path3 }
|
||||
default_backend web
|
||||
|
||||
backend xray
|
||||
server xray abns@vless.sock proto h2
|
||||
|
||||
backend server1
|
||||
server server1 abns@server1.sock proto h2
|
||||
|
||||
backend server2
|
||||
server server2 abns@server2.sock proto h2
|
||||
|
||||
backend server3
|
||||
server server3 abns@server3.sock proto h2
|
||||
|
||||
backend web
|
||||
server web /dev/shm/h1h2c.sock
|
||||
```
|
||||
|
||||
### xray 配置
|
||||
|
||||
简单的 gRPC 配置,无需 TLS,配置见文档,配置的 serviceName 可用于分流。
|
||||
|
||||
# Haproxy 使用自签证书进行双端认证(gRPC 示例)
|
||||
|
||||
这里使用自签证书双端认证加强隧道安全性(但会牺牲一点延迟,不过使用 gRPC 后感知不强),而服务端同时处理信任的证书和自签名证书,并据此分流伪装网站和隧道流量
|
||||
|
||||
其中 www.example.com 为伪装站信任证书(如白话文中申请的证书)
|
||||
|
||||
tunnel.example.com 为自签证书网址,自签证书可以参考 https://learn.microsoft.com/zh-cn/azure/application-gateway/self-signed-certificates
|
||||
|
||||
根证书 ca.crt 服务器证书 server.crt 服务器密钥 server.key
|
||||
|
||||
至少需要生成一个 server.pem,客户端可以同样使用此证书用于双端认证;或者生成两个证书,一个 client,一个 server,用于双端认证
|
||||
|
||||
需准备 fullchain.crt 用于认证( cat server.crt ca.crt > fullchain.crt ),server.pem ( cat server.crt server.key ca.crt > server.pem )用于解密
|
||||
|
||||
### haproxy_client 配置
|
||||
|
||||
```
|
||||
global
|
||||
log /dev/log local0 alert
|
||||
log /dev/log local1 alert
|
||||
stats socket /dev/shm/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user root
|
||||
group root
|
||||
daemon
|
||||
|
||||
tune.h2.initial-window-size 536870912
|
||||
tune.h2.max-concurrent-streams 512
|
||||
|
||||
ssl-default-server-options ssl-min-ver TLSv1.3
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode http
|
||||
timeout connect 5s
|
||||
timeout client 300s
|
||||
timeout server 300s
|
||||
|
||||
frontend xray
|
||||
bind 127.0.0.1:6666 proto h2
|
||||
default_backend tunnel
|
||||
|
||||
backend tunnel
|
||||
server tunnel tunnel.example.com:443 tfo allow-0rtt ssl crt /path/to/client.pem verify required ca-file /path/to/fullchain.crt sni str(tunnel.example.com) alpn h2
|
||||
# 网址自定义,和自签证书一致即可,hosts 中配置 IP 解析,sni 的 str 设定 sni,用于服务端识别
|
||||
```
|
||||
|
||||
### haproxy_server 配置
|
||||
|
||||
```
|
||||
global
|
||||
log /dev/log local0 alert
|
||||
log /dev/log local1 alert
|
||||
stats socket /dev/shm/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user root
|
||||
group root
|
||||
daemon
|
||||
|
||||
tune.h2.initial-window-size 536870912
|
||||
tune.h2.max-concurrent-streams 512
|
||||
|
||||
ssl-default-bind-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256
|
||||
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
|
||||
ssl-default-bind-options ssl-min-ver TLSv1.2
|
||||
|
||||
defaults
|
||||
log global
|
||||
mode http
|
||||
timeout connect 5s
|
||||
timeout client 300s
|
||||
timeout server 300s
|
||||
|
||||
frontend tls-in
|
||||
bind :::443 tfo allow-0rtt ssl crt /path/to/server.pem verify optional ca-file /path/to/fullchain.crt crt /path/to/www.example.com.pem alpn h2,http/1.1
|
||||
use_backend xray if { ssl_fc_sni tunnel.example.com } { ssl_c_used } { ssl_fc_alpn -i h2 } { path_beg /tunnel }
|
||||
use_backend server1 if { ssl_fc_sni atunnel.example.com } { ssl_c_used } { ssl_fc_alpn -i h2 } { path_beg /path2 }
|
||||
use_backend server2 if { ssl_fc_sni btunnel.example.com } { ssl_c_used } { ssl_fc_alpn -i h2 } { path_beg /path3 }
|
||||
use_backend server3 if { ssl_fc_sni ctunnel.example.com } { ssl_c_used } { ssl_fc_alpn -i h2 } { path_beg /path4 }
|
||||
default_backend web
|
||||
# Haproxy 支持多个 pem 解密
|
||||
# 可根据多个客户端的不同 sni 分流,也可以 path 分流,方式多样,更多 acl 见 Haproxy 文档
|
||||
|
||||
backend xray
|
||||
server xray abns@vless.sock proto h2
|
||||
|
||||
backend server1
|
||||
server server1 abns@server1.sock proto h2
|
||||
|
||||
backend server2
|
||||
server server2 abns@server2.sock proto h2
|
||||
|
||||
backend server3
|
||||
server server3 abns@server3.sock proto h2
|
||||
|
||||
backend web
|
||||
server web /dev/shm/h1h2c.sock
|
||||
```
|
||||
|
||||
### xray 配置
|
||||
|
||||
简单的 gRPC 配置,无需 TLS,配置见文档,配置的 serviceName 可用于分流。
|
|
@ -1,298 +0,0 @@
|
|||
---
|
||||
title: Nginx_TLS隧道隐藏指纹
|
||||
---
|
||||
|
||||
# 客户端服务端构建 Nginx 隧道隐藏指纹
|
||||
|
||||
网路结构:
|
||||
|
||||
xray_client ---tcp--- nginx_client ---tcp_TLS--- nginx_sever ---tcp--- xray_server
|
||||
|
||||
## 编译 nginx --with-stream
|
||||
|
||||
在客户端及服务端均编译
|
||||
|
||||
`curl -O -L http://nginx.org/download/nginx-1.22.1.tar.gz`
|
||||
|
||||
`tar -zxvf nginx-1.22.1.tar.gz`
|
||||
|
||||
`cd nginx-1.22.1`
|
||||
|
||||
`apt install gcc make` //编译依赖 gcc 以及 make
|
||||
|
||||
`./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module` //此步需要依赖一些库,根据报错安装相应 lib
|
||||
|
||||
`make && make install`
|
||||
|
||||
编译之后 nginx 文件夹位于 `/usr/local/nginx`
|
||||
|
||||
## 配置 nginx
|
||||
|
||||
编辑 nginx 配置文件 nginx.conf
|
||||
|
||||
`vim /usr/local/nginx/conf/nginx.conf`
|
||||
|
||||
服务端加入如下配置
|
||||
|
||||
服务器申请证书不再赘述,参考[白话文](https://xtls.github.io/document/level-0/ch06-certificates.html)
|
||||
|
||||
```
|
||||
stream {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
ssl_protocols TLSv1.3;
|
||||
ssl_certificate /path/to/cert/domain.crt; #crt文件位置
|
||||
ssl_certificate_key /path/to/cert/domain.key; #key文件位置
|
||||
proxy_pass unix:/dev/shm/vless.sock; #使用 domain socket
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
::: warning 注意
|
||||
|
||||
stream 部分与 http 模块并列,客户端可删除 http 部分,服务端可删除或搭建网页伪装回落
|
||||
:::
|
||||
|
||||
客户端加入如下配置
|
||||
|
||||
```
|
||||
stream {
|
||||
server {
|
||||
listen 6666;
|
||||
listen [::]:6666;
|
||||
proxy_ssl on;
|
||||
proxy_ssl_protocols TLSv1.3;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_name yourdomain.domain; #服务器域名
|
||||
proxy_pass ip:443; #服务器 ip 形如 proxy_pass 6.6.6.6:443; 或 proxy_pass [2401:0:0::1]:443;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在 `/etc/systemd/system` 文件夹中创建 `nginx.service` 文件
|
||||
|
||||
`vim /etc/systemd/system/nginx.service`
|
||||
|
||||
写入如下
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=The NGINX HTTP and reverse proxy server
|
||||
After=syslog.target network-online.target remote-fs.target nss-lookup.target
|
||||
After=xray.service
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStartPre=/usr/local/nginx/sbin/nginx -t
|
||||
ExecStart=/usr/local/nginx/sbin/nginx
|
||||
ExecReload=/usr/local/nginx/sbin/nginx -s reload
|
||||
ExecStop=/bin/kill -s QUIT $MAINPID
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
加入开机自启
|
||||
|
||||
`systemctl enable nginx`
|
||||
|
||||
## xray 配置
|
||||
|
||||
服务端 xray 配置
|
||||
|
||||
```
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "none"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"listen": "/dev/shm/vless.sock,0666",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"clients": [
|
||||
{
|
||||
"id": "uuid"
|
||||
}
|
||||
],
|
||||
"decryption": "none"
|
||||
},
|
||||
"streamSettings": {
|
||||
"network": "tcp"
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"protocol": "freedom"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
客户端 xray 配置,此处以旁路由透明代理为例
|
||||
|
||||
```
|
||||
{
|
||||
"log": {
|
||||
"loglevel": "none"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"tag": "tproxy-in",
|
||||
"port": 12345,
|
||||
"protocol": "dokodemo-door",
|
||||
"settings": {
|
||||
"network": "tcp,udp",
|
||||
"followRedirect": true
|
||||
},
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls"
|
||||
],
|
||||
"routeOnly": true
|
||||
},
|
||||
"streamSettings": {
|
||||
"sockopt": {
|
||||
"tproxy": "tproxy",
|
||||
"mark": 255
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "http",
|
||||
"port": 10808,
|
||||
"listen": "127.0.0.1",
|
||||
"protocol": "http",
|
||||
"sniffing": {
|
||||
"enabled": true,
|
||||
"destOverride": [
|
||||
"http",
|
||||
"tls"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"tag": "nginxtls",
|
||||
"protocol": "vless",
|
||||
"settings": {
|
||||
"vnext": [
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"port": 6666,
|
||||
"users": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"encryption": "none"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"streamSettings": {
|
||||
"sockopt": {
|
||||
"mark": 255
|
||||
},
|
||||
"network": "tcp"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "direct",
|
||||
"protocol": "freedom",
|
||||
"streamSettings": {
|
||||
"sockopt": {
|
||||
"mark": 255
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "block",
|
||||
"protocol": "blackhole",
|
||||
"settings": {
|
||||
"response": {
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"routing": {
|
||||
"domainMatcher": "mph",
|
||||
"domainStrategy": "AsIs",
|
||||
"rules": [
|
||||
{
|
||||
"type": "field",
|
||||
"domain": [
|
||||
"geosite:category-ads-all"
|
||||
],
|
||||
"outboundTag": "block"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"port": 123,
|
||||
"network": "udp",
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"domain": [
|
||||
"geosite:cn"
|
||||
],
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"protocol": [
|
||||
"bittorrent"
|
||||
],
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"ip": [
|
||||
"geoip:private"
|
||||
],
|
||||
"outboundTag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"inboundTag": [
|
||||
"tproxy-in"
|
||||
],
|
||||
"outboundTag": "nginxtls"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果使用透明代理需要在 iptables 或 ip6tables 配置中加入
|
||||
|
||||
```
|
||||
iptables -t mangle -A XRAY_MASK -d VSP_IPv4/32 -j RETURN
|
||||
ip6tables -t mangle -A XRAY6_MASK -d VPS_IPv6/128 -j RETURN
|
||||
```
|
||||
|
||||
## 客户端及服务端启动服务
|
||||
|
||||
`systemctl restart xray`
|
||||
|
||||
`systemctl restart nginx`
|
||||
|
||||
## 后记
|
||||
|
||||
客户端应该也是可以通过 domain socket 连接提高性能,但由于 xray outbound 不支持 ds 出站,想了半天没什么好的实现方法。如果 vnext 里支持 ds 就好了 (没有别的意思)。
|
||||
|
||||
从客户端 nginx 开始应该可以选择 http2 grpc ws 等传输方式。
|
43
package.json
43
package.json
|
@ -8,44 +8,39 @@
|
|||
"devDependencies": {
|
||||
"@types/bootstrap": "^5.2.0",
|
||||
"@types/jquery": "^3.5.14",
|
||||
"@types/mermaid": "^9.2.0",
|
||||
"@types/node": "^20.11.0",
|
||||
"@vuepress/bundler-vite": "^2.0.0-rc.0",
|
||||
"@vuepress/bundler-webpack": "2.0.0-rc.0",
|
||||
"@vuepress/plugin-back-to-top": "^2.0.0-rc.0",
|
||||
"@vuepress/plugin-debug": "^2.0.0-beta.33",
|
||||
"@vuepress/plugin-search": "^2.0.0-rc.0",
|
||||
"typescript": "^5.2.2",
|
||||
"@vuepress/bundler-vite": "2.0.0-rc.2",
|
||||
"@vuepress/bundler-webpack": "2.0.0-rc.2",
|
||||
"@vuepress/plugin-back-to-top": "^2.0.0-rc.3",
|
||||
"@vuepress/plugin-search": "2.0.0-rc.3",
|
||||
"postcss-loader": "^8.0.0",
|
||||
"prettier": "^3.2.2",
|
||||
"sass": "^1.51.0",
|
||||
"sass-loader": "^13.3.2",
|
||||
"sass-loader": "^14.1.0",
|
||||
"typescript": "^5.4.2",
|
||||
"vue-property-decorator": "^9.1.2",
|
||||
"vuepress": "^2.0.0-rc.0"
|
||||
"vuepress": "2.0.0-rc.2"
|
||||
},
|
||||
"packageManager": "pnpm@8.10.5",
|
||||
"scripts": {
|
||||
"docs:dev": "vuepress dev docs",
|
||||
"docs:build": "vuepress build docs",
|
||||
"docs:dev": "vuepress dev docs --clean-temp --clean-cache",
|
||||
"docs:build": "vuepress build docs --clean-temp --clean-cache",
|
||||
"docs:serve": "anywhere -s -h localhost -d docs/.vuepress/dist",
|
||||
"lint": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.5",
|
||||
"@vuepress/plugin-google-analytics": "2.0.0-rc.3",
|
||||
"@vuepress/plugin-register-components": "2.0.0-rc.3",
|
||||
"@vuepress/plugin-shiki": "2.0.0-rc.3",
|
||||
"@vuepress/theme-default": "2.0.0-rc.3",
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"anywhere": "^1.6.0",
|
||||
"bootstrap": "^5.2.0",
|
||||
"esbuild": "^0.19.0",
|
||||
"esbuild": "^0.20.0",
|
||||
"jquery": "^3.6.0",
|
||||
"markdown-it-footnote": "^4.0.0",
|
||||
"mermaid": "^10.7.0",
|
||||
"vuepress-plugin-mermaidjs": "^2.0.0-beta.2",
|
||||
"@vuepress/cli": "2.0.0-rc.0",
|
||||
"@vuepress/client": "2.0.0-rc.0",
|
||||
"@vuepress/core": "2.0.0-rc.0",
|
||||
"@vuepress/plugin-google-analytics": "2.0.0-rc.0",
|
||||
"@vuepress/plugin-register-components": "2.0.0-rc.0",
|
||||
"@vuepress/plugin-shiki": "2.0.0-rc.0",
|
||||
"@vuepress/theme-default": "2.0.0-rc.0",
|
||||
"@vuepress/utils": "2.0.0-rc.0",
|
||||
"anywhere": "^1.6.0",
|
||||
"vue": "^3.4.15"
|
||||
"mermaid": "^10.9.0",
|
||||
"vue": "3.3.13"
|
||||
}
|
||||
}
|
2649
pnpm-lock.yaml
generated
2649
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,20 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "esnext",
|
||||
"sourceMap": true
|
||||
"module": "ESNext",
|
||||
"target": "ES2022",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES2022"
|
||||
],
|
||||
"sourceMap": false,
|
||||
"strict": true,
|
||||
"moduleResolution": "Bundler",
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
"include": [
|
||||
"./docs/.vuepress/**/*.ts",
|
||||
"./docs/.vuepress/**/*.vue"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
4
vite.config.js
Executable file
4
vite.config.js
Executable file
|
@ -0,0 +1,4 @@
|
|||
import { splitVendorChunkPlugin } from 'vite'
|
||||
export default defineConfig({
|
||||
plugins: [splitVendorChunkPlugin()],
|
||||
})
|
Loading…
Add table
Reference in a new issue