Prettified Code!

This commit is contained in:
Meo597
2026-01-23 22:37:20 +00:00
committed by GitHub Action
parent 59bb98311e
commit 9b69a7f479
46 changed files with 1395 additions and 1312 deletions
+74 -70
View File
@@ -1,13 +1,13 @@
import { defineConfig } from "vitepress";
import llmstxt from "vitepress-plugin-llms";
import { MermaidMarkdown, MermaidPlugin } from "vitepress-plugin-mermaid";
import { defineConfig } from "vitepress"
import llmstxt from "vitepress-plugin-llms"
import { MermaidMarkdown, MermaidPlugin } from "vitepress-plugin-mermaid"
import { nav as nav } from "./menus/nav.mts";
import { nav as nav_en } from "./menus/nav.en.mts";
import { nav as nav_ru } from "./menus/nav.ru.mts";
import { sidebar as sidebar } from "./menus/sidebar.mts";
import { sidebar as sidebar_en } from "./menus/sidebar.en.mts";
import { sidebar as sidebar_ru } from "./menus/sidebar.ru.mts";
import { nav as nav } from "./menus/nav.mts"
import { nav as nav_en } from "./menus/nav.en.mts"
import { nav as nav_ru } from "./menus/nav.ru.mts"
import { sidebar as sidebar } from "./menus/sidebar.mts"
import { sidebar as sidebar_en } from "./menus/sidebar.en.mts"
import { sidebar as sidebar_ru } from "./menus/sidebar.ru.mts"
// https://vitepress.dev/reference/site-config
export default defineConfig({
@@ -22,7 +22,7 @@ export default defineConfig({
ignoreDeadLinks: false,
sitemap: {
hostname: "https://xtls.github.io",
hostname: "https://xtls.github.io"
},
markdown: {
@@ -30,23 +30,26 @@ export default defineConfig({
theme: {
dark: "dark-plus",
light: "light-plus",
light: "light-plus"
},
attrs: { leftDelimiter: "{:" },
config(md) {
md.use(MermaidMarkdown);
},
md.use(MermaidMarkdown)
}
},
vite: {
plugins: [llmstxt({ ignoreFiles: ["en/**", "ru/**"] }), MermaidPlugin()],
plugins: [
llmstxt({ ignoreFiles: ["en/**", "ru/**"] }),
MermaidPlugin()
],
optimizeDeps: {
include: ["mermaid"],
include: ["mermaid"]
},
ssr: {
noExternal: ["mermaid"],
},
noExternal: ["mermaid"]
}
},
themeConfig: {
@@ -59,13 +62,13 @@ export default defineConfig({
detailedView: true,
miniSearch: {
options: {
tokenize: (str) => str.split(/[\s,,。、]+/),
},
tokenize: (str) => str.split(/[\s,,。、]+/)
}
},
translations: {
button: {
buttonText: "搜索",
buttonAriaLabel: "搜索",
buttonAriaLabel: "搜索"
},
modal: {
displayDetails: "显示详细列表",
@@ -75,11 +78,11 @@ export default defineConfig({
footer: {
selectText: "选择",
navigateText: "切换",
closeText: "关闭",
},
},
},
},
closeText: "关闭"
}
}
}
}
},
darkModeSwitchLabel: "深色模式",
@@ -92,43 +95,44 @@ export default defineConfig({
outline: {
level: [2, 4],
label: "页面导航",
label: "页面导航"
},
sidebar: sidebar,
socialLinks: [
{ icon: "github", link: "https://github.com/XTLS/Xray-core" },
{ icon: "github", link: "https://github.com/XTLS/Xray-core" }
],
editLink: {
pattern: "https://github.com/XTLS/Xray-docs-next/edit/main/docs/:path",
text: "帮助我们改善此页面!",
pattern:
"https://github.com/XTLS/Xray-docs-next/edit/main/docs/:path",
text: "帮助我们改善此页面!"
},
lastUpdated: {
text: "最近更改",
formatOptions: {
dateStyle: "short",
timeStyle: "short",
},
timeStyle: "short"
}
},
docFooter: {
prev: "上一页",
next: "下一页",
next: "下一页"
},
footer: {
message: "根据 CC-BY-SA 4.0 许可协议授权",
copyright: "版权所有 © 2020-至今 Project X 社区",
},
copyright: "版权所有 © 2020-至今 Project X 社区"
}
},
locales: {
root: {
label: "简体中文",
lang: "zh",
lang: "zh"
},
en: {
@@ -144,13 +148,13 @@ export default defineConfig({
tokenize: (str) =>
str
.split(/[\s.,;!?'"(){}[\]\-_+=&%$#@~`^<>|\\]+/)
.filter(Boolean),
},
.filter(Boolean)
}
},
translations: {
button: {
buttonText: "Search",
buttonAriaLabel: "Search",
buttonAriaLabel: "Search"
},
modal: {
displayDetails: "Show detailed list",
@@ -160,11 +164,11 @@ export default defineConfig({
footer: {
selectText: "Select",
navigateText: "Navigate",
closeText: "Close",
},
},
},
},
closeText: "Close"
}
}
}
}
},
darkModeSwitchLabel: "Appearance",
@@ -174,33 +178,33 @@ export default defineConfig({
returnToTopLabel: "Return to top",
outline: {
label: "On this page",
label: "On this page"
},
sidebar: sidebar_en,
editLink: {
text: "Help us improve this page on GitHub!",
text: "Help us improve this page on GitHub!"
},
lastUpdated: {
text: "Last Updated",
formatOptions: {
dateStyle: "short",
timeStyle: "short",
},
timeStyle: "short"
}
},
docFooter: {
prev: "Previous page",
next: "Next page",
next: "Next page"
},
footer: {
message: "Licensed under CC-BY-SA 4.0",
copyright: "Copyright © 2020-Present Project X Community",
},
},
copyright: "Copyright © 2020-Present Project X Community"
}
}
},
ru: {
@@ -216,13 +220,13 @@ export default defineConfig({
tokenize: (str) =>
str
.split(/[\s.,;!?'"(){}[\]\-_+=&%$#@~`^<>|\\]+/)
.filter(Boolean),
},
.filter(Boolean)
}
},
translations: {
button: {
buttonText: "Поиск",
buttonAriaLabel: "Поиск",
buttonAriaLabel: "Поиск"
},
modal: {
displayDetails: "Показать подробный список",
@@ -232,11 +236,11 @@ export default defineConfig({
footer: {
selectText: "Выбрать",
navigateText: "Переключить",
closeText: "Закрыть",
},
},
},
},
closeText: "Закрыть"
}
}
}
}
},
darkModeSwitchLabel: "Внешний вид",
@@ -246,34 +250,34 @@ export default defineConfig({
returnToTopLabel: "Вернуться наверх",
outline: {
label: "Содержание страницы",
label: "Содержание страницы"
},
sidebar: sidebar_ru,
editLink: {
text: "Помогите нам улучшить эту страницу!",
text: "Помогите нам улучшить эту страницу!"
},
lastUpdated: {
text: "Последние изменения",
formatOptions: {
dateStyle: "short",
timeStyle: "short",
},
timeStyle: "short"
}
},
docFooter: {
prev: "Предыдущая страница",
next: "Следующая страница",
next: "Следующая страница"
},
footer: {
message: "Лицензия CC-BY-SA 4.0",
copyright:
"Авторские права 2020-настоящее время Сообщество Project X",
},
},
},
},
});
"Авторские права 2020-настоящее время Сообщество Project X"
}
}
}
}
})
+8 -8
View File
@@ -1,4 +1,4 @@
import type { DefaultTheme } from "vitepress";
import type { DefaultTheme } from "vitepress"
export const nav: DefaultTheme.Config["nav"] = [
{ text: "Homepage", link: "/en" },
@@ -9,8 +9,8 @@ export const nav: DefaultTheme.Config["nav"] = [
{ text: "Basic Configuration", link: "/en/config/" },
{ text: "Inbound Protocols", link: "/en/config/inbounds/" },
{ text: "Outbound Protocols", link: "/en/config/outbounds/" },
{ text: "Transports", link: "/en/config/transports/" },
],
{ text: "Transports", link: "/en/config/transports/" }
]
},
{
text: "Usage Guide",
@@ -18,12 +18,12 @@ export const nav: DefaultTheme.Config["nav"] = [
{ text: "Quick Start", link: "/en/document/" },
{
text: "Absolute Beginner's Plain Guide",
link: "/en/document/level-0/",
link: "/en/document/level-0/"
},
{ text: "Beginner Skills", link: "/en/document/level-1/" },
{ text: "Advanced Skills", link: "/en/document/level-2/" },
],
{ text: "Advanced Skills", link: "/en/document/level-2/" }
]
},
{ text: "Developer Guide", link: "/en/development/" },
{ text: "Sponsor & Donation & NFTs", link: "/en/about/sponsor.md" },
];
{ text: "Sponsor & Donation & NFTs", link: "/en/about/sponsor.md" }
]
+7 -7
View File
@@ -1,4 +1,4 @@
import type { DefaultTheme } from "vitepress";
import type { DefaultTheme } from "vitepress"
export const nav: DefaultTheme.Config["nav"] = [
{ text: "首页", link: "/" },
@@ -9,8 +9,8 @@ export const nav: DefaultTheme.Config["nav"] = [
{ text: "基础配置", link: "/config/" },
{ text: "入站协议", link: "/config/inbounds/" },
{ text: "出站协议", link: "/config/outbounds/" },
{ text: "底层传输", link: "/config/transports/" },
],
{ text: "底层传输", link: "/config/transports/" }
]
},
{
text: "使用指南",
@@ -18,9 +18,9 @@ export const nav: DefaultTheme.Config["nav"] = [
{ text: "快速入门", link: "/document/" },
{ text: "小小白白话文", link: "/document/level-0/" },
{ text: "入门技巧", link: "/document/level-1/" },
{ text: "进阶技巧", link: "/document/level-2/" },
],
{ text: "进阶技巧", link: "/document/level-2/" }
]
},
{ text: "开发指南", link: "/development/" },
{ text: "赞助 & 捐款 & NFTs", link: "/about/sponsor.md" },
];
{ text: "赞助 & 捐款 & NFTs", link: "/about/sponsor.md" }
]
+8 -8
View File
@@ -1,4 +1,4 @@
import type { DefaultTheme } from "vitepress";
import type { DefaultTheme } from "vitepress"
export const nav: DefaultTheme.Config["nav"] = [
{ text: "Главная", link: "/ru" },
@@ -9,8 +9,8 @@ export const nav: DefaultTheme.Config["nav"] = [
{ text: "Базовая конфигурация", link: "/ru/config/" },
{ text: "Входящие подключения", link: "/ru/config/inbounds/" },
{ text: "Исходящие подключения", link: "/ru/config/outbounds/" },
{ text: "Транспортный уровень", link: "/ru/config/transports/" },
],
{ text: "Транспортный уровень", link: "/ru/config/transports/" }
]
},
{
text: "Руководство по использованию",
@@ -18,12 +18,12 @@ export const nav: DefaultTheme.Config["nav"] = [
{ text: "Быстрый старт", link: "/ru/document/" },
{
text: "Простыми словами",
link: "/ru/document/level-0/",
link: "/ru/document/level-0/"
},
{ text: "Базовые навыки", link: "/ru/document/level-1/" },
{ text: "Продвинутые навыки", link: "/ru/document/level-2/" },
],
{ text: "Продвинутые навыки", link: "/ru/document/level-2/" }
]
},
{ text: "Руководство разработчика", link: "/ru/development/" },
{ text: "Sponsor & Donation & NFTs", link: "/ru/about/sponsor.md" },
];
{ text: "Sponsor & Donation & NFTs", link: "/ru/about/sponsor.md" }
]
+97 -67
View File
@@ -1,4 +1,4 @@
import type { DefaultTheme } from "vitepress";
import type { DefaultTheme } from "vitepress"
export const sidebar: DefaultTheme.Config["sidebar"] = {
"/en/config/": [
@@ -11,14 +11,17 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Fallback", link: "/en/config/features/fallback.md" },
{
text: "Browser Dialer",
link: "/en/config/features/browser_dialer.md",
link: "/en/config/features/browser_dialer.md"
},
{
text: "Environment Variables",
link: "/en/config/features/env.md"
},
{ text: "Environment Variables", link: "/en/config/features/env.md" },
{
text: "Multiple Configurations",
link: "/en/config/features/multiple.md",
},
],
link: "/en/config/features/multiple.md"
}
]
},
{
text: "Basic Configuration",
@@ -35,10 +38,13 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Reverse Proxy", link: "/en/config/reverse.md" },
{ text: "Routing", link: "/en/config/routing.md" },
{ text: "Statistics", link: "/en/config/stats.md" },
{ text: "Transport (uTLS, REALITY)", link: "/en/config/transport.md" },
{
text: "Transport (uTLS, REALITY)",
link: "/en/config/transport.md"
},
{ text: "Metrics", link: "/en/config/metrics.md" },
{ text: "Observatory", link: "/en/config/observatory.md" },
],
{ text: "Observatory", link: "/en/config/observatory.md" }
]
},
{
text: "Inbound Protocols",
@@ -47,20 +53,23 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Tunnel (dokodemo-door)",
link: "/en/config/inbounds/tunnel.md",
link: "/en/config/inbounds/tunnel.md"
},
{ text: "HTTP", link: "/en/config/inbounds/http.md" },
{ text: "Shadowsocks", link: "/en/config/inbounds/shadowsocks.md" },
{
text: "Shadowsocks",
link: "/en/config/inbounds/shadowsocks.md"
},
{ text: "Socks", link: "/en/config/inbounds/socks.md" },
{ text: "Trojan", link: "/en/config/inbounds/trojan.md" },
{
text: "VLESS (XTLS Vision Seed)",
link: "/en/config/inbounds/vless.md",
link: "/en/config/inbounds/vless.md"
},
{ text: "VMess", link: "/en/config/inbounds/vmess.md" },
{ text: "Wireguard", link: "/en/config/inbounds/wireguard.md" },
{ text: "TUN", link: "/en/config/inbounds/tun.md" },
],
{ text: "TUN", link: "/en/config/inbounds/tun.md" }
]
},
{
text: "Outbound Protocols",
@@ -71,21 +80,24 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "DNS", link: "/en/config/outbounds/dns.md" },
{
text: "Freedom (fragment, noises)",
link: "/en/config/outbounds/freedom.md",
link: "/en/config/outbounds/freedom.md"
},
{ text: "HTTP", link: "/en/config/outbounds/http.md" },
{ text: "Loopback", link: "/en/config/outbounds/loopback.md" },
{ text: "Shadowsocks", link: "/en/config/outbounds/shadowsocks.md" },
{
text: "Shadowsocks",
link: "/en/config/outbounds/shadowsocks.md"
},
{ text: "Socks", link: "/en/config/outbounds/socks.md" },
{ text: "Trojan", link: "/en/config/outbounds/trojan.md" },
{
text: "VLESS (XTLS Vision Seed)",
link: "/en/config/outbounds/vless.md",
link: "/en/config/outbounds/vless.md"
},
{ text: "VMess", link: "/en/config/outbounds/vmess.md" },
{ text: "Wireguard", link: "/en/config/outbounds/wireguard.md" },
{ text: "Hysteria", link: "/en/config/outbounds/hysteria.md" },
],
{ text: "Hysteria", link: "/en/config/outbounds/hysteria.md" }
]
},
{
text: "Transports",
@@ -95,15 +107,18 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "RAW", link: "/en/config/transports/raw.md" },
{
text: "XHTTP: Beyond REALITY",
link: "/en/config/transports/xhttp.md",
link: "/en/config/transports/xhttp.md"
},
{ text: "mKCP", link: "/en/config/transports/mkcp.md" },
{ text: "gRPC", link: "/en/config/transports/grpc.md" },
{ text: "WebSocket", link: "/en/config/transports/websocket.md" },
{ text: "HTTPUpgrade", link: "/en/config/transports/httpupgrade.md" },
{ text: "Hysteria", link: "/en/config/transports/hysteria.md" },
],
},
{
text: "HTTPUpgrade",
link: "/en/config/transports/httpupgrade.md"
},
{ text: "Hysteria", link: "/en/config/transports/hysteria.md" }
]
}
],
"/en/document/": [
{
@@ -114,8 +129,11 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Installation", link: "/en/document/install.md" },
{ text: "Configuration & Run", link: "/en/document/config.md" },
{ text: "Command Arguments", link: "/en/document/command.md" },
{ text: "Contribute to Project X", link: "/en/document/document.md" },
],
{
text: "Contribute to Project X",
link: "/en/document/document.md"
}
]
},
{
text: "Absolute Beginner's Guide",
@@ -124,41 +142,41 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "[Chapter 1] Preface",
link: "/en/document/level-0/ch01-preface.md",
link: "/en/document/level-0/ch01-preface.md"
},
{
text: "[Chapter 2] Preparation",
link: "/en/document/level-0/ch02-preparation.md",
link: "/en/document/level-0/ch02-preparation.md"
},
{
text: "[Chapter 3] Remote Login (SSH)",
link: "/en/document/level-0/ch03-ssh.md",
link: "/en/document/level-0/ch03-ssh.md"
},
{
text: "[Chapter 4] Security",
link: "/en/document/level-0/ch04-security.md",
link: "/en/document/level-0/ch04-security.md"
},
{
text: "[Chapter 5] Website Building",
link: "/en/document/level-0/ch05-webpage.md",
link: "/en/document/level-0/ch05-webpage.md"
},
{
text: "[Chapter 6] Certificate Management",
link: "/en/document/level-0/ch06-certificates.md",
link: "/en/document/level-0/ch06-certificates.md"
},
{
text: "[Chapter 7] Xray Server",
link: "/en/document/level-0/ch07-xray-server.md",
link: "/en/document/level-0/ch07-xray-server.md"
},
{
text: "[Chapter 8] Xray Clients",
link: "/en/document/level-0/ch08-xray-clients.md",
link: "/en/document/level-0/ch08-xray-clients.md"
},
{
text: "[Chapter 9] Appendix",
link: "/en/document/level-0/ch09-appendix.md",
},
],
link: "/en/document/level-0/ch09-appendix.md"
}
]
},
{
text: "Beginner Skills",
@@ -167,26 +185,29 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Analysis of Fallbacks",
link: "/en/document/level-1/fallbacks-lv1.md",
link: "/en/document/level-1/fallbacks-lv1.md"
},
{
text: "Analysis of Routing (Part 1)",
link: "/en/document/level-1/routing-lv1-part1.md",
link: "/en/document/level-1/routing-lv1-part1.md"
},
{
text: "Analysis of Routing (Part 2)",
link: "/en/document/level-1/routing-lv1-part2.md",
link: "/en/document/level-1/routing-lv1-part2.md"
},
{
text: "Working Modes of Xray",
link: "/en/document/level-1/work.md"
},
{ text: "Working Modes of Xray", link: "/en/document/level-1/work.md" },
{
text: "SNI Fallback",
link: "/en/document/level-1/fallbacks-with-sni.md",
link: "/en/document/level-1/fallbacks-with-sni.md"
},
{
text: "Traffic Splitting via DNS",
link: "/en/document/level-1/routing-with-dns.md",
},
],
link: "/en/document/level-1/routing-with-dns.md"
}
]
},
{
text: "Advanced Skills",
@@ -195,38 +216,38 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Transparent Proxy Basics",
link: "/en/document/level-2/transparent_proxy/transparent_proxy.md",
link: "/en/document/level-2/transparent_proxy/transparent_proxy.md"
},
{
text: "TProxy Transparent Proxy",
link: "/en/document/level-2/tproxy.md",
link: "/en/document/level-2/tproxy.md"
},
{
text: "TProxy (IPv4 and IPv6)",
link: "/en/document/level-2/tproxy_ipv4_and_ipv6.md",
link: "/en/document/level-2/tproxy_ipv4_and_ipv6.md"
},
{
text: "Hide Fingerprint with Nginx/Haproxy TLS Tunnel",
link: "/en/document/level-2/nginx_or_haproxy_tls_tunnel.md",
link: "/en/document/level-2/nginx_or_haproxy_tls_tunnel.md"
},
{
text: "GID Transparent Proxy",
link: "/en/document/level-2/iptables_gid.md",
link: "/en/document/level-2/iptables_gid.md"
},
{
text: "Outbound Traffic Redirection",
link: "/en/document/level-2/redirect.md",
link: "/en/document/level-2/redirect.md"
},
{
text: "Enhance Security with Cloudflare Warp",
link: "/en/document/level-2/warp.md",
link: "/en/document/level-2/warp.md"
},
{
text: "Traffic Statistics",
link: "/en/document/level-2/traffic_stats.md",
},
],
},
link: "/en/document/level-2/traffic_stats.md"
}
]
}
],
"/en/development/": [
{
@@ -238,22 +259,31 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Design Goals", link: "/en/development/intro/design.md" },
{
text: "Development Guidelines",
link: "/en/development/intro/guide.md",
},
],
link: "/en/development/intro/guide.md"
}
]
},
{
text: "Protocol Details",
collapsed: false,
items: [
{ text: "VLESS Protocol", link: "/en/development/protocols/vless.md" },
{ text: "VMess Protocol", link: "/en/development/protocols/vmess.md" },
{
text: "VLESS Protocol",
link: "/en/development/protocols/vless.md"
},
{
text: "VMess Protocol",
link: "/en/development/protocols/vmess.md"
},
{
text: "Mux.Cool Protocol",
link: "/en/development/protocols/muxcool.md",
link: "/en/development/protocols/muxcool.md"
},
{ text: "mKCP Protocol", link: "/en/development/protocols/mkcp.md" },
],
},
],
};
{
text: "mKCP Protocol",
link: "/en/development/protocols/mkcp.md"
}
]
}
]
}
+61 -55
View File
@@ -1,4 +1,4 @@
import type { DefaultTheme } from "vitepress";
import type { DefaultTheme } from "vitepress"
export const sidebar: DefaultTheme.Config["sidebar"] = {
"/config/": [
@@ -11,11 +11,11 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Fallback 回落", link: "/config/features/fallback.md" },
{
text: "Browser Dialer",
link: "/config/features/browser_dialer.md",
link: "/config/features/browser_dialer.md"
},
{ text: "环境变量", link: "/config/features/env.md" },
{ text: "多文件配置", link: "/config/features/multiple.md" },
],
{ text: "多文件配置", link: "/config/features/multiple.md" }
]
},
{
text: "基础配置",
@@ -32,10 +32,13 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "反向代理", link: "/config/reverse.md" },
{ text: "路由", link: "/config/routing.md" },
{ text: "统计信息", link: "/config/stats.md" },
{ text: "传输方式(uTLS、REALITY", link: "/config/transport.md" },
{
text: "传输方式(uTLS、REALITY",
link: "/config/transport.md"
},
{ text: "Metrics", link: "/config/metrics.md" },
{ text: "连接观测", link: "/config/observatory.md" },
],
{ text: "连接观测", link: "/config/observatory.md" }
]
},
{
text: "入站协议",
@@ -44,7 +47,7 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Tunneldokodemo-door",
link: "/config/inbounds/tunnel.md",
link: "/config/inbounds/tunnel.md"
},
{ text: "HTTP", link: "/config/inbounds/http.md" },
{ text: "Shadowsocks", link: "/config/inbounds/shadowsocks.md" },
@@ -52,12 +55,12 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Trojan", link: "/config/inbounds/trojan.md" },
{
text: "VLESSXTLS Vision Seed",
link: "/config/inbounds/vless.md",
link: "/config/inbounds/vless.md"
},
{ text: "VMess", link: "/config/inbounds/vmess.md" },
{ text: "Wireguard", link: "/config/inbounds/wireguard.md" },
{ text: "TUN", link: "/config/inbounds/tun.md" },
],
{ text: "TUN", link: "/config/inbounds/tun.md" }
]
},
{
text: "出站协议",
@@ -68,7 +71,7 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "DNS", link: "/config/outbounds/dns.md" },
{
text: "Freedomfragment、noises",
link: "/config/outbounds/freedom.md",
link: "/config/outbounds/freedom.md"
},
{ text: "HTTP", link: "/config/outbounds/http.md" },
{ text: "Loopback", link: "/config/outbounds/loopback.md" },
@@ -77,12 +80,12 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Trojan", link: "/config/outbounds/trojan.md" },
{
text: "VLESSXTLS Vision Seed",
link: "/config/outbounds/vless.md",
link: "/config/outbounds/vless.md"
},
{ text: "VMess", link: "/config/outbounds/vmess.md" },
{ text: "Wireguard", link: "/config/outbounds/wireguard.md" },
{ text: "Hysteria", link: "/config/outbounds/hysteria.md" },
],
{ text: "Hysteria", link: "/config/outbounds/hysteria.md" }
]
},
{
text: "底层传输",
@@ -92,15 +95,15 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "RAW", link: "/config/transports/raw.md" },
{
text: "XHTTP: Beyond REALITY",
link: "/config/transports/xhttp.md",
link: "/config/transports/xhttp.md"
},
{ text: "mKCP", link: "/config/transports/mkcp.md" },
{ text: "gRPC", link: "/config/transports/grpc.md" },
{ text: "WebSocket", link: "/config/transports/websocket.md" },
{ text: "HTTPUpgrade", link: "/config/transports/httpupgrade.md" },
{ text: "Hysteria", link: "/config/transports/hysteria.md" },
],
},
{ text: "Hysteria", link: "/config/transports/hysteria.md" }
]
}
],
"/document/": [
{
@@ -111,8 +114,8 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "下载安装", link: "/document/install.md" },
{ text: "配置运行", link: "/document/config.md" },
{ text: "命令参数", link: "/document/command.md" },
{ text: "为 Project X 的文档贡献", link: "/document/document.md" },
],
{ text: "为 Project X 的文档贡献", link: "/document/document.md" }
]
},
{
text: "小小白白话文",
@@ -121,41 +124,41 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "【第 1 章】 小小白白话文",
link: "/document/level-0/ch01-preface.md",
link: "/document/level-0/ch01-preface.md"
},
{
text: "【第 2 章】原料准备篇",
link: "/document/level-0/ch02-preparation.md",
link: "/document/level-0/ch02-preparation.md"
},
{
text: "【第 3 章】远程登录篇",
link: "/document/level-0/ch03-ssh.md",
link: "/document/level-0/ch03-ssh.md"
},
{
text: "【第 4 章】安全防护篇",
link: "/document/level-0/ch04-security.md",
link: "/document/level-0/ch04-security.md"
},
{
text: "【第 5 章】网站建设篇",
link: "/document/level-0/ch05-webpage.md",
link: "/document/level-0/ch05-webpage.md"
},
{
text: "【第 6 章】证书管理篇",
link: "/document/level-0/ch06-certificates.md",
link: "/document/level-0/ch06-certificates.md"
},
{
text: "【第 7 章】Xray 服务器篇",
link: "/document/level-0/ch07-xray-server.md",
link: "/document/level-0/ch07-xray-server.md"
},
{
text: "【第 8 章】Xray 客户端篇",
link: "/document/level-0/ch08-xray-clients.md",
link: "/document/level-0/ch08-xray-clients.md"
},
{
text: "【第 9 章】附录",
link: "/document/level-0/ch09-appendix.md",
},
],
link: "/document/level-0/ch09-appendix.md"
}
]
},
{
text: "入门技巧",
@@ -164,26 +167,26 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "回落 (fallbacks) 功能简析",
link: "/document/level-1/fallbacks-lv1.md",
link: "/document/level-1/fallbacks-lv1.md"
},
{
text: "路由 (routing) 功能简析(上)",
link: "/document/level-1/routing-lv1-part1.md",
link: "/document/level-1/routing-lv1-part1.md"
},
{
text: "路由 (routing) 功能简析(下)",
link: "/document/level-1/routing-lv1-part2.md",
link: "/document/level-1/routing-lv1-part2.md"
},
{ text: "Xray 的工作模式", link: "/document/level-1/work.md" },
{
text: "SNI 回落",
link: "/document/level-1/fallbacks-with-sni.md",
link: "/document/level-1/fallbacks-with-sni.md"
},
{
text: "用 DNS 实现精准境内外分流",
link: "/document/level-1/routing-with-dns.md",
},
],
link: "/document/level-1/routing-with-dns.md"
}
]
},
{
text: "进阶技巧",
@@ -192,26 +195,29 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "透明代理入门",
link: "/document/level-2/transparent_proxy/transparent_proxy.md",
link: "/document/level-2/transparent_proxy/transparent_proxy.md"
},
{ text: "TProxy 透明代理", link: "/document/level-2/tproxy.md" },
{
text: "TProxy 透明代理(ipv4 and ipv6",
link: "/document/level-2/tproxy_ipv4_and_ipv6.md",
link: "/document/level-2/tproxy_ipv4_and_ipv6.md"
},
{
text: "Nginx 或 Haproxy 搭建 TLS 隧道隐藏指纹",
link: "/document/level-2/nginx_or_haproxy_tls_tunnel.md",
link: "/document/level-2/nginx_or_haproxy_tls_tunnel.md"
},
{
text: "GID 透明代理",
link: "/document/level-2/iptables_gid.md"
},
{ text: "GID 透明代理", link: "/document/level-2/iptables_gid.md" },
{ text: "出站流量重定向", link: "/document/level-2/redirect.md" },
{
text: "通过 Cloudflare Warp 增强代理安全性",
link: "/document/level-2/warp.md",
link: "/document/level-2/warp.md"
},
{ text: "流量统计", link: "/document/level-2/traffic_stats.md" },
],
},
{ text: "流量统计", link: "/document/level-2/traffic_stats.md" }
]
}
],
"/development/": [
{
@@ -221,8 +227,8 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{ text: "编译", link: "/development/intro/compile.md" },
{ text: "设计目标", link: "/development/intro/design.md" },
{ text: "开发规范", link: "/development/intro/guide.md" },
],
{ text: "开发规范", link: "/development/intro/guide.md" }
]
},
{
text: "协议详解",
@@ -232,10 +238,10 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "VMess 协议", link: "/development/protocols/vmess.md" },
{
text: "Mux.Cool 协议",
link: "/development/protocols/muxcool.md",
link: "/development/protocols/muxcool.md"
},
{ text: "mKCP 协议", link: "/development/protocols/mkcp.md" },
],
},
],
};
{ text: "mKCP 协议", link: "/development/protocols/mkcp.md" }
]
}
]
}
+81 -81
View File
@@ -1,4 +1,4 @@
import type { DefaultTheme } from "vitepress";
import type { DefaultTheme } from "vitepress"
export const sidebar: DefaultTheme.Config["sidebar"] = {
"/ru/config/": [
@@ -9,25 +9,25 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Глубокий анализ XTLS",
link: "/ru/config/features/xtls.md",
link: "/ru/config/features/xtls.md"
},
{
text: "Fallback",
link: "/ru/config/features/fallback.md",
link: "/ru/config/features/fallback.md"
},
{
text: "Browser Dialer",
link: "/ru/config/features/browser_dialer.md",
link: "/ru/config/features/browser_dialer.md"
},
{
text: "Переменные окружения",
link: "/ru/config/features/env.md",
link: "/ru/config/features/env.md"
},
{
text: "Конфигурация из нескольких файлов",
link: "/ru/config/features/multiple.md",
},
],
link: "/ru/config/features/multiple.md"
}
]
},
{
text: "Базовая конфигурация",
@@ -41,7 +41,7 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Входящие подключения", link: "/ru/config/inbound.md" },
{
text: "Исходящие подключения",
link: "/ru/config/outbound.md",
link: "/ru/config/outbound.md"
},
{ text: "Локальные политики", link: "/ru/config/policy.md" },
{ text: "Обратный прокси", link: "/ru/config/reverse.md" },
@@ -49,14 +49,14 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "Статистика", link: "/ru/config/stats.md" },
{
text: "Способы передачи",
link: "/ru/config/transport.md",
link: "/ru/config/transport.md"
},
{ text: "Метрики", link: "/ru/config/metrics.md" },
{
text: "Мониторинг подключений",
link: "/ru/config/observatory.md",
},
],
link: "/ru/config/observatory.md"
}
]
},
{
text: "Входящие подключения",
@@ -65,23 +65,23 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Tunnel (dokodemo-door)",
link: "/ru/config/inbounds/tunnel.md",
link: "/ru/config/inbounds/tunnel.md"
},
{ text: "HTTP", link: "/ru/config/inbounds/http.md" },
{
text: "Shadowsocks",
link: "/ru/config/inbounds/shadowsocks.md",
link: "/ru/config/inbounds/shadowsocks.md"
},
{ text: "Socks", link: "/ru/config/inbounds/socks.md" },
{ text: "Trojan", link: "/ru/config/inbounds/trojan.md" },
{
text: "VLESS (XTLS Vision Seed)",
link: "/ru/config/inbounds/vless.md",
link: "/ru/config/inbounds/vless.md"
},
{ text: "VMess", link: "/ru/config/inbounds/vmess.md" },
{ text: "Wireguard", link: "/ru/config/inbounds/wireguard.md" },
{ text: "TUN", link: "/ru/config/inbounds/tun.md" },
],
{ text: "TUN", link: "/ru/config/inbounds/tun.md" }
]
},
{
text: "Исходящие подключения",
@@ -90,35 +90,35 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Blackhole",
link: "/ru/config/outbounds/blackhole.md",
link: "/ru/config/outbounds/blackhole.md"
},
{ text: "DNS", link: "/ru/config/outbounds/dns.md" },
{
text: "Freedom (fragment, noises)",
link: "/ru/config/outbounds/freedom.md",
link: "/ru/config/outbounds/freedom.md"
},
{ text: "HTTP", link: "/ru/config/outbounds/http.md" },
{ text: "Loopback", link: "/ru/config/outbounds/loopback.md" },
{
text: "Shadowsocks",
link: "/ru/config/outbounds/shadowsocks.md",
link: "/ru/config/outbounds/shadowsocks.md"
},
{ text: "Socks", link: "/ru/config/outbounds/socks.md" },
{ text: "Trojan", link: "/ru/config/outbounds/trojan.md" },
{
text: "VLESS (XTLS Vision Seed)",
link: "/ru/config/outbounds/vless.md",
link: "/ru/config/outbounds/vless.md"
},
{ text: "VMess", link: "/ru/config/outbounds/vmess.md" },
{
text: "Wireguard",
link: "/ru/config/outbounds/wireguard.md",
link: "/ru/config/outbounds/wireguard.md"
},
{
text: "Hysteria 2",
link: "/ru/config/outbounds/hysteria.md",
},
],
link: "/ru/config/outbounds/hysteria.md"
}
]
},
{
text: "Способы передачи",
@@ -128,24 +128,24 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
{ text: "RAW", link: "/ru/config/transports/raw.md" },
{
text: "XHTTP: За пределами REALITY",
link: "/ru/config/transports/xhttp.md",
link: "/ru/config/transports/xhttp.md"
},
{ text: "mKCP", link: "/ru/config/transports/mkcp.md" },
{ text: "gRPC", link: "/ru/config/transports/grpc.md" },
{
text: "WebSocket",
link: "/ru/config/transports/websocket.md",
link: "/ru/config/transports/websocket.md"
},
{
text: "HTTPUpgrade",
link: "/ru/config/transports/httpupgrade.md",
link: "/ru/config/transports/httpupgrade.md"
},
{
text: "Hysteria",
link: "/ru/config/transports/hysteria.md",
},
],
},
link: "/ru/config/transports/hysteria.md"
}
]
}
],
"/ru/document/": [
{
@@ -155,15 +155,15 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Загрузка и установка",
link: "/ru/document/install.md",
link: "/ru/document/install.md"
},
{ text: "Настройка и запуск", link: "/ru/document/config.md" },
{ text: "Параметры команды", link: "/ru/document/command.md" },
{
text: "Вклад в документацию Project X",
link: "/ru/document/document.md",
},
],
link: "/ru/document/document.md"
}
]
},
{
text: "Простыми словами",
@@ -172,41 +172,41 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "[Глава 1] Руководство для новичков простым языком",
link: "/ru/document/level-0/ch01-preface.md",
link: "/ru/document/level-0/ch01-preface.md"
},
{
text: "[Глава 2] Подготовка",
link: "/ru/document/level-0/ch02-preparation.md",
link: "/ru/document/level-0/ch02-preparation.md"
},
{
text: "[Глава 3] Удаленный вход",
link: "/ru/document/level-0/ch03-ssh.md",
link: "/ru/document/level-0/ch03-ssh.md"
},
{
text: "[Глава 4] Защита безопасности",
link: "/ru/document/level-0/ch04-security.md",
link: "/ru/document/level-0/ch04-security.md"
},
{
text: "[Глава 5] Создание веб-сайта",
link: "/ru/document/level-0/ch05-webpage.md",
link: "/ru/document/level-0/ch05-webpage.md"
},
{
text: "[Глава 6] Управление сертификатами",
link: "/ru/document/level-0/ch06-certificates.md",
link: "/ru/document/level-0/ch06-certificates.md"
},
{
text: "[Глава 7] Сервер Xray",
link: "/ru/document/level-0/ch07-xray-server.md",
link: "/ru/document/level-0/ch07-xray-server.md"
},
{
text: "[Глава 8] Клиент Xray",
link: "/ru/document/level-0/ch08-xray-clients.md",
link: "/ru/document/level-0/ch08-xray-clients.md"
},
{
text: "[Глава 9] Приложение",
link: "/ru/document/level-0/ch09-appendix.md",
},
],
link: "/ru/document/level-0/ch09-appendix.md"
}
]
},
{
text: "Советы для начинающих",
@@ -215,29 +215,29 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Краткий анализ функции Fallbacks",
link: "/ru/document/level-1/fallbacks-lv1.md",
link: "/ru/document/level-1/fallbacks-lv1.md"
},
{
text: "Краткий анализ функции маршрутизации (Часть 1)",
link: "/ru/document/level-1/routing-lv1-part1.md",
link: "/ru/document/level-1/routing-lv1-part1.md"
},
{
text: "Краткий анализ функции маршрутизации (Часть 2)",
link: "/ru/document/level-1/routing-lv1-part2.md",
link: "/ru/document/level-1/routing-lv1-part2.md"
},
{
text: "Режимы работы Xray",
link: "/ru/document/level-1/work.md",
link: "/ru/document/level-1/work.md"
},
{
text: "SNI Fallback",
link: "/ru/document/level-1/fallbacks-with-sni.md",
link: "/ru/document/level-1/fallbacks-with-sni.md"
},
{
text: "Достижение точного разделения трафика (внутренний/международный) с помощью DNS",
link: "/ru/document/level-1/routing-with-dns.md",
},
],
link: "/ru/document/level-1/routing-with-dns.md"
}
]
},
{
text: "Продвинутые советы",
@@ -246,38 +246,38 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Введение в прозрачный прокси",
link: "/ru/document/level-2/transparent_proxy/transparent_proxy.md",
link: "/ru/document/level-2/transparent_proxy/transparent_proxy.md"
},
{
text: "Прозрачный прокси TProxy",
link: "/ru/document/level-2/tproxy.md",
link: "/ru/document/level-2/tproxy.md"
},
{
text: "Прозрачный прокси TProxy (IPv4 и IPv6)",
link: "/ru/document/level-2/tproxy_ipv4_and_ipv6.md",
link: "/ru/document/level-2/tproxy_ipv4_and_ipv6.md"
},
{
text: "Создание TLS-туннеля с Nginx или Haproxy для скрытия отпечатков",
link: "/ru/document/level-2/nginx_or_haproxy_tls_tunnel.md",
link: "/ru/document/level-2/nginx_or_haproxy_tls_tunnel.md"
},
{
text: "Прозрачный прокси GID",
link: "/ru/document/level-2/iptables_gid.md",
link: "/ru/document/level-2/iptables_gid.md"
},
{
text: "Перенаправление исходящего трафика",
link: "/ru/document/level-2/redirect.md",
link: "/ru/document/level-2/redirect.md"
},
{
text: "Улучшение безопасности прокси с помощью Cloudflare Warp",
link: "/ru/document/level-2/warp.md",
link: "/ru/document/level-2/warp.md"
},
{
text: "Статистика трафика",
link: "/ru/document/level-2/traffic_stats.md",
},
],
},
link: "/ru/document/level-2/traffic_stats.md"
}
]
}
],
"/ru/development/": [
{
@@ -287,17 +287,17 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Компиляция",
link: "/ru/development/intro/compile.md",
link: "/ru/development/intro/compile.md"
},
{
text: "Дизайн",
link: "/ru/development/intro/design.md",
link: "/ru/development/intro/design.md"
},
{
text: "Принципы разработки",
link: "/ru/development/intro/guide.md",
},
],
link: "/ru/development/intro/guide.md"
}
]
},
{
text: "Детали протоколов",
@@ -305,21 +305,21 @@ export const sidebar: DefaultTheme.Config["sidebar"] = {
items: [
{
text: "Протокол VLESS",
link: "/ru/development/protocols/vless.md",
link: "/ru/development/protocols/vless.md"
},
{
text: "Протокол VMess",
link: "/ru/development/protocols/vmess.md",
link: "/ru/development/protocols/vmess.md"
},
{
text: "Протокол Mux.Cool",
link: "/ru/development/protocols/muxcool.md",
link: "/ru/development/protocols/muxcool.md"
},
{
text: "Протокол mKCP",
link: "/ru/development/protocols/mkcp.md",
},
],
},
],
};
link: "/ru/development/protocols/mkcp.md"
}
]
}
]
}
+10 -10
View File
@@ -1,25 +1,25 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import { ref, onMounted, onUnmounted } from "vue"
const visible = ref(false);
const THRESHOLD = 300;
const visible = ref(false)
const THRESHOLD = 300
function onScroll() {
visible.value = window.scrollY > THRESHOLD;
visible.value = window.scrollY > THRESHOLD
}
function backToTop() {
window.scrollTo({ top: 0, behavior: "smooth" });
window.scrollTo({ top: 0, behavior: "smooth" })
}
onMounted(() => {
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
});
onScroll()
window.addEventListener("scroll", onScroll, { passive: true })
})
onUnmounted(() => {
window.removeEventListener("scroll", onScroll);
});
window.removeEventListener("scroll", onScroll)
})
</script>
<template>
@@ -1,45 +1,45 @@
<script setup lang="ts">
import contributorsMap from "../../.generated/contributors.json";
import { useRoute, useData } from "vitepress";
import { computed } from "vue";
import contributorsMap from "../../.generated/contributors.json"
import { useRoute, useData } from "vitepress"
import { computed } from "vue"
type Contributor = { name: string; email?: string; commits: number };
type Contributor = { name: string; email?: string; commits: number }
const route = useRoute();
const { lang } = useData();
const route = useRoute()
const { lang } = useData()
const list = computed(() => {
const map = contributorsMap as Record<string, Contributor[]>;
const map = contributorsMap as Record<string, Contributor[]>
const raw = route.path;
const raw = route.path
const candidates = new Set<string>();
const candidates = new Set<string>()
const noHtml = raw.replace(/\.html$/, "");
candidates.add(raw);
candidates.add(noHtml);
const noHtml = raw.replace(/\.html$/, "")
candidates.add(raw)
candidates.add(noHtml)
// /foo -> /foo/ and /foo/ -> /foo
for (const p of [raw, noHtml]) {
if (p.endsWith("/")) candidates.add(p.slice(0, -1));
else candidates.add(p + "/");
if (p.endsWith("/")) candidates.add(p.slice(0, -1))
else candidates.add(p + "/")
}
for (const key of candidates) {
if (map[key]?.length) return map[key];
if (map[key]?.length) return map[key]
}
return [];
});
return []
})
const t = computed(() => {
const l = (lang.value || "en").toLowerCase();
const l = (lang.value || "en").toLowerCase()
const dict = {
en: { contributors: "Contributors", commits: "commits" },
zh: { contributors: "贡献者", commits: "次提交" },
ru: { contributors: "Участники", commits: "коммитов" },
} as const;
return (dict as any)[l] || (dict as any)[l.split("-")[0]] || dict.en;
});
ru: { contributors: "Участники", commits: "коммитов" }
} as const
return (dict as any)[l] || (dict as any)[l.split("-")[0]] || dict.en
})
</script>
<template>
@@ -51,7 +51,12 @@ const t = computed(() => {
<ul class="list">
<li v-for="c in list" :key="c.email || c.name" class="item">
<img class="avatar" :src="c.avatarUrl" :alt="c.name" loading="lazy" />
<img
class="avatar"
:src="c.avatarUrl"
:alt="c.name"
loading="lazy"
/>
<div class="main">
<div class="row">
<span class="name">{{ c.name }}</span>
@@ -1,48 +1,50 @@
<script setup lang="ts">
import statusMap from "../../.generated/i18n-status.json";
import { useRoute, useData } from "vitepress";
import { computed } from "vue";
import statusMap from "../../.generated/i18n-status.json"
import { useRoute, useData } from "vitepress"
import { computed } from "vue"
const route = useRoute();
const { lang } = useData();
const route = useRoute()
const { lang } = useData()
const info = computed(() => {
const map = statusMap as Record<string, any>;
const raw = route.path;
const map = statusMap as Record<string, any>
const raw = route.path
const keys = [
raw,
raw.replace(/\.html$/, ""),
raw.endsWith("/") ? raw.slice(0, -1) : raw + "/",
raw.replace(/\.html$/, "").endsWith("/")
? raw.replace(/\.html$/, "").slice(0, -1)
: raw.replace(/\.html$/, "") + "/",
];
for (const k of keys) if (map[k]) return map[k];
return null;
});
: raw.replace(/\.html$/, "") + "/"
]
for (const k of keys) if (map[k]) return map[k]
return null
})
const isZh = computed(() => (lang.value || "").toLowerCase().startsWith("zh"));
const isZh = computed(() =>
(lang.value || "").toLowerCase().startsWith("zh")
)
const text = computed(() => {
const l = (lang.value || "en").toLowerCase();
const l = (lang.value || "en").toLowerCase()
const dict: any = {
en: {
title: "Translation notice",
body: "This translation may be outdated. Please refer to the Chinese original.",
missing:
"This page is not translated yet. Please refer to the Chinese original.",
go: "View Chinese original",
go: "View Chinese original"
},
ru: {
title: "Уведомление о переводе",
body: "Этот перевод может быть устаревшим. Пожалуйста, обратитесь к оригинальной китайской версии.",
missing:
"Эта страница ещё не переведена. Пожалуйста, обратитесь к оригинальной версии на китайском языке.",
go: "Посмотреть оригинальную китайскую версию",
},
};
return dict[l] || dict[l.split("-")[0]] || dict.en;
});
go: "Посмотреть оригинальную китайскую версию"
}
}
return dict[l] || dict[l.split("-")[0]] || dict.en
})
</script>
<template>
+19 -19
View File
@@ -1,41 +1,41 @@
// Given from https://vitepress.dev/guide/extending-default-theme
import DefaultTheme from "vitepress/theme";
import DefaultTheme from "vitepress/theme"
import "./style/index.css";
import "./style/index.css"
import mediumZoom from "medium-zoom";
import { onMounted, watch, nextTick } from "vue";
import { useRoute } from "vitepress";
import mediumZoom from "medium-zoom"
import { onMounted, watch, nextTick } from "vue"
import { useRoute } from "vitepress"
import { h } from "vue";
import TranslationNotice from "./components/TranslationNotice.vue";
import PageContributors from "./components/PageContributors.vue";
import BackToTop from "./components/BackToTop.vue";
import { h } from "vue"
import TranslationNotice from "./components/TranslationNotice.vue"
import PageContributors from "./components/PageContributors.vue"
import BackToTop from "./components/BackToTop.vue"
export default {
extends: DefaultTheme,
setup() {
const route = useRoute();
const route = useRoute()
const initZoom = () => {
// mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' }); // default
mediumZoom(".main img", { background: "var(--vp-c-bg)" }); // Enable this feature for all images unless {data-zoomable} is explicitly added.
};
mediumZoom(".main img", { background: "var(--vp-c-bg)" }) // Enable this feature for all images unless {data-zoomable} is explicitly added.
}
onMounted(() => {
initZoom();
});
initZoom()
})
watch(
() => route.path,
() => nextTick(() => initZoom())
);
)
},
Layout() {
return h(DefaultTheme.Layout, null, {
"doc-before": () => h(TranslationNotice),
"doc-after": () => h(PageContributors),
"layout-bottom": () => h(BackToTop),
});
},
};
"layout-bottom": () => h(BackToTop)
})
}
}
+11 -6
View File
@@ -105,24 +105,29 @@
<!-- The information between the BODY and /BODY tags is displayed.-->
<body>
<h1>Enter the main heading, usually the same as the title.</h1>
<p>Be <b>bold</b> in stating your key points. Put them in a list:</p>
<p>
Be <b>bold</b> in stating your key points. Put them in a list:
</p>
<ul>
<li>The first item in your list</li>
<li>The second item; <i>italicize</i> key words</li>
</ul>
<p>Improve your image by including an image.</p>
<p>
<img src="https://i.imgur.com/SEBww.jpg" alt="A Great HTML Resource" />
<img
src="https://i.imgur.com/SEBww.jpg"
alt="A Great HTML Resource"
/>
</p>
<p>
Add a link to your favorite
<a href="https://www.dummies.com/">Web site</a>. Break up your page
with a horizontal rule or two.
<a href="https://www.dummies.com/">Web site</a>. Break up your
page with a horizontal rule or two.
</p>
<hr />
<p>
Finally, link to <a href="page2.html">another page</a> in your own Web
site.
Finally, link to <a href="page2.html">another page</a> in your own
Web site.
</p>
<!-- And add a copyright notice.-->
<p>&#169; Wiley Publishing, 2011</p>
+8 -2
View File
@@ -104,7 +104,10 @@ bash -c "$(curl -L wgcf-cli.vercel.app)"
"protocol": "wireguard",
"settings": {
"secretKey": "6CRVRLgFwGajnikoVOPTDNZnDhx3EydhPsMgpxHfBCY=",
"address": ["172.16.0.2/32", "2606:4700:110:857a:6a95:fe27:1870:2a9d/128"],
"address": [
"172.16.0.2/32",
"2606:4700:110:857a:6a95:fe27:1870:2a9d/128"
],
"peers": [
{
"publicKey": "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=",
@@ -128,7 +131,10 @@ bash -c "$(curl -L wgcf-cli.vercel.app)"
"protocol": "wireguard",
"settings": {
"secretKey": "我的私钥",
"address": ["172.16.0.2/32", "2606:4700:110:8949:fed8:2642:a640:c8e1/128"],
"address": [
"172.16.0.2/32",
"2606:4700:110:8949:fed8:2642:a640:c8e1/128"
],
"peers": [
{
"publicKey": "Warp公钥",
+1 -1
View File
@@ -59,7 +59,7 @@ Usage: Solves the issue where Nginx's h2c service cannot be compatible with http
Note: When `fallbacks` `alpn` contains `"h2"`, [Inbound TLS](../transport.md#tlsobject) needs to set `"alpn":["h2","http/1.1"]` to support h2 access.
::: tip
The `alpn` set in Fallback matches the *actually negotiated* ALPN, whereas the `alpn` set in Inbound TLS is the list of *optional* ALPNs during the handshake. The meanings are different.
The `alpn` set in Fallback matches the _actually negotiated_ ALPN, whereas the `alpn` set in Inbound TLS is the list of _optional_ ALPNs during the handshake. The meanings are different.
:::
> `path`: string
+1 -1
View File
@@ -17,7 +17,7 @@ Use the following environment variables in Linux to enable a global HTTP proxy f
- `export http_proxy=http://127.0.0.1:8080/` (Address must be changed to your configured HTTP inbound proxy address)
- `export https_proxy=$http_proxy`
:::
:::
## InboundConfigurationObject
+1 -1
View File
@@ -54,7 +54,7 @@ A custom string and its mapped UUID are equivalent. This means you can identify
- Write `"id": "我爱🍉老师1314"`,
- Or write `"id": "5783a3e7-e373-51cd-8642-c83782b807c5"` (This UUID is the UUID mapping of `我爱🍉老师1314`)
:::
:::
The mapping standard is described in [VLESS UUID Mapping Standard: Mapping Custom Strings to UUIDv5](https://github.com/XTLS/Xray-core/issues/158).
+99 -99
View File
@@ -143,108 +143,108 @@ To get better visualization output, you can use [Netdata](https://github.com/net
```yaml
xray:
name: 'xray'
name: "xray"
update_every: 2
url: 'http://127.0.0.1:11111/debug/vars'
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
- 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>
+1 -1
View File
@@ -91,7 +91,7 @@ The number of recent probe results to keep.
Probe timeout. Format is the same as `interval` above.
::: tip
The working principle of Burst Observatory is to immediately schedule probe tasks for each matched outbound at every `interval` * `sampling` (hereinafter referred to as the probe cycle). However, within each task's cycle, the probe is executed at a random time. This means compared to `observatory` (Background Connection Observatory), the fingerprint of this detector is less obvious. But if `interval` is set too small, or `sampling` is too large causing frequent probing, the fingerprint will be more obvious.
The working principle of Burst Observatory is to immediately schedule probe tasks for each matched outbound at every `interval` \* `sampling` (hereinafter referred to as the probe cycle). However, within each task's cycle, the probe is executed at a random time. This means compared to `observatory` (Background Connection Observatory), the fingerprint of this detector is less obvious. But if `interval` is set too small, or `sampling` is too large causing frequent probing, the fingerprint will be more obvious.
`interval` and `sampling` jointly affect the sensitivity of failover and recovery. When a node fails probes continuously, it takes at fastest 1 probe cycle to mark the node as faulty, and at slowest 2 probe cycles. Recovering from failure requires one successful probe, which depends on the probe density; at slowest, it takes 1 probe cycle.
:::
+1 -1
View File
@@ -68,7 +68,7 @@ When `interval` is 0 and `"packets": "tlshello"` is set, the fragmented Client H
> `noises`: array
UDP noise, used to send some random data as "noise" before sending a UDP connection. Presence of this structure implies enablement. It might deceive sniffers, or it might disrupt normal connections. *Use at your own risk.* For this reason, it bypasses port 53 because that breaks DNS.
UDP noise, used to send some random data as "noise" before sending a UDP connection. Presence of this structure implies enablement. It might deceive sniffers, or it might disrupt normal connections. _Use at your own risk._ For this reason, it bypasses port 53 because that breaks DNS.
It is an array where multiple noise packets to be sent can be defined. A single element in the array is defined as follows:
+1 -1
View File
@@ -58,7 +58,7 @@ Encryption method. The client will use the configured encryption method to send
It is not recommended to use `"none"` or `"zero"` pseudo-encryption methods without enabling TLS encryption and enforcing certificate verification. Regardless of the encryption method used, the VMess packet header is protected by encryption and authentication.
Note: `"auto"` only determines the AES hardware acceleration support status of the *client*. If the *server* does not support AES hardware acceleration, you still need to manually set it to `chacha20-poly1305`. This is very important because Chacha20-Poly1305 takes about 48% more time than AES-128-GCM on platforms supporting AES acceleration, but on platforms *without* AES acceleration, AES-128-GCM takes over 2000% more time than Chacha20-Poly1305.
Note: `"auto"` only determines the AES hardware acceleration support status of the _client_. If the _server_ does not support AES hardware acceleration, you still need to manually set it to `chacha20-poly1305`. This is very important because Chacha20-Poly1305 takes about 48% more time than AES-128-GCM on platforms supporting AES acceleration, but on platforms _without_ AES acceleration, AES-128-GCM takes over 2000% more time than Chacha20-Poly1305.
> `experiments`: string
+1 -1
View File
@@ -21,7 +21,7 @@ The general working principle of the reverse proxy is as follows:
- `portal`
- If the `portal` receives a request and the domain matches, it indicates response data sent by the `bridge`. This connection will be used to establish the reverse tunnel.
- If the `portal` receives a request and the domain does *not* match, it indicates a connection from a public user. This connection data will be forwarded to the bridge.
- If the `portal` receives a request and the domain does _not_ match, it indicates a connection from a public user. This connection data will be forwarded to the bridge.
- The `bridge` performs dynamic load balancing based on traffic volume.
+8 -6
View File
@@ -8,8 +8,6 @@ Transport specifies a stable method for data transmission. Generally, both ends
`StreamSettingsObject` corresponds to the `streamSettings` item in inbound or outbound configurations. Each inbound or outbound can be configured with different transport settings independently, and `streamSettings` can be set to perform some transport configurations.
```json
{
"network": "raw",
@@ -105,8 +103,6 @@ Specific configurations related to transparent proxying.
### TLSObject
```json
{
"serverName": "xray.com",
@@ -311,7 +307,10 @@ Adjusts the underlying socket options of the connection used when querying ECH r
"show": false,
"target": "example.com:443",
"xver": 0,
"serverNames": ["example.com", "[www.example.com](https://www.example.com)"],
"serverNames": [
"example.com",
"[www.example.com](https://www.example.com)"
],
"privateKey": "",
"minClientVer": "",
"maxClientVer": "",
@@ -712,6 +711,7 @@ TL;DR: Connecting to server requires waiting for DNS result; finishing DNS query
> Tony: Chicken or egg first?
Detailed explanation:
1. Trigger: Proxy server (`proxy.com`). Built-in DNS server, non-Local mode.
2. Xray attempts to establish TCP connection to `proxy.com`. **Before** that, query `proxy.com` via built-in DNS.
3. Built-in DNS connects to `dns.com` to query IP of `proxy.com`.
@@ -723,6 +723,7 @@ Detailed explanation:
9. Good Game!
Solutions:
- Change traffic splitting for built-in DNS server.
- Use Hosts.
- ~~If you still don't know the solution, don't use this feature.~~
@@ -770,10 +771,11 @@ TCP congestion control algorithm. Linux only.
Not configuring means using system default.
::: tip Common Algorithms
- bbr (Recommended)
- cubic
- reno
:::
:::
::: tip
Run `sysctl net.ipv4.tcp_congestion_control` to get system default.
+1 -1
View File
@@ -140,7 +140,7 @@ Used with the camouflage type `"dns"`. You can fill in any domain name.
The native KCP protocol uses a fixed header of 24 bytes, while mKCP modifies this to 18 bytes for data packets and 16 bytes for acknowledgement (ACK) packets. Smaller headers help evade characteristic detection and increase transmission speed.
Additionally, native KCP's single ACK packet can only acknowledge the receipt of one data packet. This means that when KCP needs to acknowledge the receipt of 100 data packets, it sends 24 *100 = 2400 bytes of data. This includes a large amount of repetitive header data, causing bandwidth waste. mKCP compresses multiple ACK packets; 100 ACK packets require only 16 + 2 + 100* 4 = 418 bytes, which is equivalent to one-sixth of the native size.
Additionally, native KCP's single ACK packet can only acknowledge the receipt of one data packet. This means that when KCP needs to acknowledge the receipt of 100 data packets, it sends 24 _100 = 2400 bytes of data. This includes a large amount of repetitive header data, causing bandwidth waste. mKCP compresses multiple ACK packets; 100 ACK packets require only 16 + 2 + 100_ 4 = 418 bytes, which is equivalent to one-sixth of the native size.
### ACK Packet Retransmission
+10 -10
View File
@@ -28,8 +28,8 @@ mKCP is a UDP-based protocol; all communication is transmitted using UDP.
### Packet
| 4 Bytes | 2 Bytes | L Bytes |
| :--- | :--- | :--- |
| 4 Bytes | 2 Bytes | L Bytes |
| :--------------- | :------------ | :----------- |
| Authentication A | Data Length L | Segment Part |
Where:
@@ -39,9 +39,9 @@ Where:
### Data Segment
| 2 Bytes | 1 Byte | 1 Byte | 4 Bytes | 4 Bytes | 4 Bytes | 2 Bytes | Len Bytes |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| Identifier Conv | Command Cmd | Option Opt | Timestamp Ts | Sequence Sn | Unacknowledged Una | Length Len | Data |
| 2 Bytes | 1 Byte | 1 Byte | 4 Bytes | 4 Bytes | 4 Bytes | 2 Bytes | Len Bytes |
| :-------------- | :---------- | :--------- | :----------- | :---------- | :----------------- | :--------- | :-------- |
| Identifier Conv | Command Cmd | Option Opt | Timestamp Ts | Sequence Sn | Unacknowledged Una | Length Len | Data |
Where:
@@ -56,9 +56,9 @@ Where:
### ACK Segment
| 2 Bytes | 1 Byte | 1 Byte | 4 Bytes | 4 Bytes | 4 Bytes | 2 Bytes | Len * 4 Bytes |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| Identifier Conv | Command Cmd | Option Opt | Window Wnd | Next Receive Sn | Timestamp Ts | Length Len | Received Sns |
| 2 Bytes | 1 Byte | 1 Byte | 4 Bytes | 4 Bytes | 4 Bytes | 2 Bytes | Len \* 4 Bytes |
| :-------------- | :---------- | :--------- | :--------- | :-------------- | :----------- | :--------- | :------------- |
| Identifier Conv | Command Cmd | Option Opt | Window Wnd | Next Receive Sn | Timestamp Ts | Length Len | Received Sns |
Where:
@@ -76,8 +76,8 @@ Note:
### Ping (Heartbeat) Segment
| 2 Bytes | 1 Byte | 1 Byte | 4 Bytes | 4 Bytes | 4 Bytes |
| :--- | :--- | :--- | :--- | :--- | :--- |
| 2 Bytes | 1 Byte | 1 Byte | 4 Bytes | 4 Bytes | 4 Bytes |
| :-------------- | :---------- | :--------- | :----------------- | :-------------- | :---------- |
| Identifier Conv | Command Cmd | Option Opt | Unacknowledged Una | Next Receive Sn | Latency Rto |
Where:
+40 -40
View File
@@ -41,47 +41,47 @@ Mux.Cool uses a symmetric transmission format, meaning the client and server sen
### Frame Format
| 2 bytes | L bytes | X bytes |
| :--- | :--- | :--- |
| 2 bytes | L bytes | X bytes |
| :---------------- | :------- | :--------- |
| Metadata Length L | Metadata | Extra Data |
### Metadata
There are several types of metadata. All types of metadata include ID and Opt items, with meanings as follows:
* ID: Unique identifier for the sub-connection
* For general Mux sub-connections, the ID accumulates starting from 1.
* For [Single XUDP](https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go) implemented by Xray, the ID is always 0.
* Opt:
* D(0x01): Has extra data
- ID: Unique identifier for the sub-connection
- For general Mux sub-connections, the ID accumulates starting from 1.
- For [Single XUDP](https://github.com/XTLS/Xray-core/blob/main/common/xudp/xudp.go) implemented by Xray, the ID is always 0.
- Opt:
- D(0x01): Has extra data
When option Opt(D) is enabled, the extra data format is as follows:
| 2 bytes | X-2 bytes |
| :--- | :--- |
| Length X-2 | Data |
| 2 bytes | X-2 bytes |
| :--------- | :-------- |
| Length X-2 | Data |
### New Sub-connection (New)
| 2 bytes | 1 byte | 1 byte | 1 byte | 2 bytes | 1 byte | A bytes | 8 bytes |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| ID | 0x01 | Option Opt | Network Type N | Port | Address Type T | Address A | Global ID (XUDP) |
| 2 bytes | 1 byte | 1 byte | 1 byte | 2 bytes | 1 byte | A bytes | 8 bytes |
| :------ | :----- | :--------- | :------------- | :------ | :------------- | :-------- | :--------------- |
| ID | 0x01 | Option Opt | Network Type N | Port | Address Type T | Address A | Global ID (XUDP) |
Where:
* Network Type N:
* 0x01: TCP, indicating that the traffic of the current sub-connection should be sent to the target via TCP.
* 0x02: UDP, indicating that the traffic of the current sub-connection should be sent to the target via UDP.
* Address Type T:
* 0x01: IPv4
* 0x02: Domain name
* 0x03: IPv6
* Address A:
* When T = 0x01, A is a 4-byte IPv4 address;
* When T = 0x02, A is a 1-byte length (L) + L bytes of domain name;
* When T = 0x03, A is a 16-byte IPv6 address;
* Global ID (XUDP):
* The client calculates a global unique ID for the UDP source 2-tuple. The server uses this to ensure that when XUDP reconnects after disconnection, it still uses the same port to communicate with the target.
- Network Type N:
- 0x01: TCP, indicating that the traffic of the current sub-connection should be sent to the target via TCP.
- 0x02: UDP, indicating that the traffic of the current sub-connection should be sent to the target via UDP.
- Address Type T:
- 0x01: IPv4
- 0x02: Domain name
- 0x03: IPv6
- Address A:
- When T = 0x01, A is a 4-byte IPv4 address;
- When T = 0x02, A is a 1-byte length (L) + L bytes of domain name;
- When T = 0x03, A is a 16-byte IPv6 address;
- Global ID (XUDP):
- The client calculates a global unique ID for the UDP source 2-tuple. The server uses this to ensure that when XUDP reconnects after disconnection, it still uses the same port to communicate with the target.
When creating a new sub-connection, if Opt(D) is enabled, the data carried in this frame needs to be sent to the target host.
@@ -89,37 +89,37 @@ When creating a new sub-connection, if Opt(D) is enabled, the data carried in th
TCP
| 2 bytes | 1 byte | 1 byte |
| :--- | :--- | :--- |
| ID | 0x02 | Option Opt |
| 2 bytes | 1 byte | 1 byte |
| :------ | :----- | :--------- |
| ID | 0x02 | Option Opt |
UDP
| 2 bytes | 1 byte | 1 byte | 1 byte | 2 bytes | 1 byte | A bytes |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| ID | 0x02 | Option Opt | Network Type N | Port | Address Type T | Address A |
| 2 bytes | 1 byte | 1 byte | 1 byte | 2 bytes | 1 byte | A bytes |
| :------ | :----- | :--------- | :------------- | :------ | :------------- | :-------- |
| ID | 0x02 | Option Opt | Network Type N | Port | Address Type T | Address A |
When keeping a sub-connection, if Opt(D) is enabled, the data carried in this frame needs to be sent to the target host.
XUDP adds the UDP address after Opt(D), formatted the same as in "New Sub-connection", but without the Global ID.
### End Sub-connection (End)
| 2 bytes | 1 byte | 1 byte |
| :--- | :--- | :--- |
| ID | 0x03 | Option Opt |
| 2 bytes | 1 byte | 1 byte |
| :------ | :----- | :--------- |
| ID | 0x03 | Option Opt |
When closing a sub-connection, if Opt(D) is enabled, the data carried in this frame needs to be sent to the target host.
### Keep Connection (KeepAlive)
| 2 bytes | 1 byte | 1 byte |
| :--- | :--- | :--- |
| ID | 0x04 | Option Opt |
| 2 bytes | 1 byte | 1 byte |
| :------ | :----- | :--------- |
| ID | 0x04 | Option Opt |
When keeping the connection:
* If Opt(D) is enabled, the data carried in this frame must be discarded.
* The ID can be a random value.
- If Opt(D) is enabled, the data carried in this frame must be discarded.
- The ID can be a random value.
## Application
+6 -6
View File
@@ -4,12 +4,12 @@ VLESS is a stateless lightweight transport protocol that serves as a bridge betw
## Request & Response
| 1 Byte | 16 Bytes | 1 Byte | M Bytes | 1 Byte | 2 Bytes | 1 Byte | S Bytes | X Bytes |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| Protocol Version | Equivalent UUID | Addons Length M | Addons ProtoBuf | Command | Port | Address Type | Address | Request Data |
| 1 Byte | 16 Bytes | 1 Byte | M Bytes | 1 Byte | 2 Bytes | 1 Byte | S Bytes | X Bytes |
| :--------------- | :-------------- | :-------------- | :-------------- | :------ | :------ | :----------- | :------ | :----------- |
| Protocol Version | Equivalent UUID | Addons Length M | Addons ProtoBuf | Command | Port | Address Type | Address | Request Data |
| 1 Byte | 1 Byte | N Bytes | Y Bytes |
| :--- | :--- | :--- | :--- |
| 1 Byte | 1 Byte | N Bytes | Y Bytes |
| :-------------------------------- | :-------------- | :-------------- | :------------ |
| Protocol Version, same as request | Addons Length N | Addons ProtoBuf | Response Data |
VLESS has had the above structure since the second alpha version, ALPHA 2 (BETA is the fifth test version):
@@ -37,7 +37,7 @@ It seems only VLESS allows optional embedded ProtoBuf. It is a data exchange for
The origin was an article I read stating that SS has some shortcomings, such as lacking an error reporting mechanism design, meaning clients cannot take further actions based on different errors.
(I don't agree that all errors should be reported; otherwise, active probing cannot be prevented. In the next beta, the server can return a string of custom information.)
So I realized an extensible structure is important. In the future, it could also carry things like dynamic port commands. Not just responses, requests also need a similar structure.
I originally planned to design TLV myself, but then realized ProtoBuf *is* this structure, a ready-made wheel perfectly suitable for this task, with good language support.
I originally planned to design TLV myself, but then realized ProtoBuf _is_ this structure, a ready-made wheel perfectly suitable for this task, with good language support.
Currently, "Addons" only contain Scheduler and SchedulerV, which replace MessName and MessSeed. **When you don't need them, "Addons Length" is 0, so there is no ProtoBuf serialization/deserialization overhead.** Actually, I prefer to call this process "splicing" because that's what pb effectively does in principle, with minimal overhead. The spliced bytes are very compact, hardly different from the ALPHA scheme. Those interested can output and compare them separately.
+15 -15
View File
@@ -43,9 +43,9 @@ VMess uses an asymmetric format, meaning the request sent by the client and the
## Client Request
| 16 bytes | X bytes | Remaining part |
| ------------------ | -------------- | -------------- |
| Authentication Info| Command Section| Data Section |
| 16 bytes | X bytes | Remaining part |
| ------------------- | --------------- | -------------- |
| Authentication Info | Command Section | Data Section |
### Authentication Info
@@ -63,15 +63,15 @@ The command section is encrypted using AES-128-CFB:
- Key: MD5(User ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
- IV: MD5(X + X + X + X), where X = []byte(Time used for generating authentication info) (8 bytes, Big Endian)
| 1 byte | 16 bytes | 16 bytes | 1 byte | 1 byte | 4 bits | 4 bits | 1 byte | 1 byte | 2 bytes | 1 byte | N bytes | P bytes | 4 bytes |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| Version Ver | Data Encryption IV | Data Encryption Key | Response Auth V | Option Opt | Margin P | Encryption Sec | Reserved | Command Cmd | Port | Address Type T | Address A | Random Value | Checksum F |
| 1 byte | 16 bytes | 16 bytes | 1 byte | 1 byte | 4 bits | 4 bits | 1 byte | 1 byte | 2 bytes | 1 byte | N bytes | P bytes | 4 bytes |
| :---------: | :----------------: | :-----------------: | :-------------: | :--------: | :------: | :------------: | :------: | :---------: | :-----: | :------------: | :-------: | :----------: | :--------: |
| Version Ver | Data Encryption IV | Data Encryption Key | Response Auth V | Option Opt | Margin P | Encryption Sec | Reserved | Command Cmd | Port | Address Type T | Address A | Random Value | Checksum F |
Option Opt details: (When a bit is 1, the option is enabled)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| X | X | X | X | X | M | R | S |
| X | X | X | X | X | M | R | S |
Where:
@@ -111,8 +111,8 @@ Where:
When Opt(S) is enabled, the data section uses this format. The actual request data is split into several small chunks, each formatted as follows. The server verifies all small chunks before forwarding them according to the basic format.
| 2 bytes | L bytes |
| :---: | :---: |
| 2 bytes | L bytes |
| :------: | :---------: |
| Length L | Data Packet |
Where:
@@ -141,8 +141,8 @@ Depending on the encryption method, the data packet format is as follows:
The response header data is encrypted using AES-128-CFB, with IV being MD5(Data Encryption IV) and Key being MD5(Data Encryption Key). The actual response data varies depending on encryption settings.
| 1 byte | 1 byte | 1 byte | 1 byte | M bytes | Remaining part |
| :--- | :--- | :--- | :--- | :--- | :--- |
| 1 byte | 1 byte | 1 byte | 1 byte | M bytes | Remaining part |
| :-------------- | :--------- | :---------- | :--------------- | :-------------- | :------------------- |
| Response Auth V | Option Opt | Command Cmd | Command Length M | Command Content | Actual Response Data |
Where:
@@ -159,9 +159,9 @@ Where:
### Dynamic Port Command
| 1 byte | 2 bytes | 16 bytes | 2 bytes | 1 byte | 1 byte |
| :--- | :--- | :--- | :--- | :--- | :--- |
| Reserved | Port | User ID | AlterID | User Level | Validity Time T |
| 1 byte | 2 bytes | 16 bytes | 2 bytes | 1 byte | 1 byte |
| :------- | :------ | :------- | :------ | :--------- | :-------------- |
| Reserved | Port | User ID | AlterID | User Level | Validity Time T |
Where:
+2 -2
View File
@@ -74,7 +74,7 @@ When `-config` is not specified, Xray will attempt to load `config.json` from th
- Working Directory
- The path specified by `Xray.location.asset` in [Environment Variables](../config/features/env.md#resource-file-path)
:::
:::
```
xray run -dump
@@ -219,7 +219,7 @@ When `-config` is not specified, Xray will attempt to load `config.json` from th
- Working Directory
- The path specified by `Xray.location.asset` in [Environment Variables](../config/features/env.md#resource-file-path)
:::
:::
### xray mldsa65
+1 -1
View File
@@ -66,7 +66,7 @@ A so-called "Airport" is a "Line Provider" (VPN/Proxy Service). They handle the
The other side of the "convenience" coin is "risk." Based on the technical characteristics and market situation of "Airports," the risks are at least:
1. **"Airports" can fully access user information**: All user traces on the Internet *inevitably* pass through and are *very likely* stored on their servers for a long time. These records are not bound by any legally effective user privacy agreements (**peeping, recording your every move**).
1. **"Airports" can fully access user information**: All user traces on the Internet _inevitably_ pass through and are _very likely_ stored on their servers for a long time. These records are not bound by any legally effective user privacy agreements (**peeping, recording your every move**).
2. **"Airports" lack market regulation**: There are inevitably malicious merchants aiming at fraud (**active exit scams/running away**).
3. **"Airports" face regulatory pressure**: While big airports are relatively secure, they cannot avoid attracting attention. In 2020, several large airports suspended operations or ran away, severely interfering with users' normal usage (**passive exit scams/forced shutdown**).
4. **"Airport" technical levels are hard to determine**: Line quality varies greatly, and deceptive practices are common (**slow speeds, frequent drops, inability to connect**).
+8 -8
View File
@@ -8,9 +8,9 @@ You need to obtain a healthy VPS whose IP is not blocked, and complete the follo
1. Install the **Debian 10 64bit** system in the VPS management panel.
2. Make a note of the VPS IP address (this article will use `"100.200.300.400"` to represent it).
::: tip
This is a deliberately written illegal IP; please replace it with your real IP.
:::
::: tip
This is a deliberately written illegal IP; please replace it with your real IP.
:::
3. Make a note of the VPS SSH remote login port.
4. Make a note of the SSH remote login username and password.
@@ -36,15 +36,15 @@ This is **not** a real, usable URL; please replace it with your real URL.
## 2.3 Software to Install on Your Local Computer
1. **SSH Remote Login Tool**
* Windows: [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)
* macOS/Linux: Terminal
- Windows: [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)
- macOS/Linux: Terminal
2. **Remote File Copy Tool**
* Windows: [WinSCP](https://winscp.net/eng/index.php)
* macOS/Linux: Terminal
- Windows: [WinSCP](https://winscp.net/eng/index.php)
- macOS/Linux: Terminal
3. **Reliable Text Editor**
* Windows/macOS/Linux: [VSCode](https://code.visualstudio.com)
- Windows/macOS/Linux: [VSCode](https://code.visualstudio.com)
## 2.4 Your Progress
+5 -5
View File
@@ -24,7 +24,7 @@ Now, follow me step by step.
Any setting updates in PuTTY must be manually saved to the Session again, otherwise, they will be lost when you close the program.
:::
1. Click `Open` to enter the SSH connection window. Enter your username and password as shown below to connect to your VPS. (This article assumes the default username is `root`. Also, when typing passwords in Linux, **no asterisks `******` will appear**. This prevents password length leakage—your keyboard isn't broken!)
1. Click `Open` to enter the SSH connection window. Enter your username and password as shown below to connect to your VPS. (This article assumes the default username is `root`. Also, when typing passwords in Linux, **no asterisks `\*\*\*\***` will appear\*\*. This prevents password length leakage—your keyboard isn't broken!)
![SSH Remote Login](./ch03-img04-ssh-login.png)
@@ -56,10 +56,10 @@ Any setting updates in PuTTY must be manually saved to the Session again, otherw
3. Basic Linux commands for beginners:
| Code | Command Name | Description |
| :---: | :---: | :---: |
| `cmd-01` | `apt update` | Check for software updates |
| `cmd-02` | `apt upgrade` | Execute software updates |
| Code | Command Name | Description |
| :------: | :-----------: | :------------------------: |
| `cmd-01` | `apt update` | Check for software updates |
| `cmd-02` | `apt upgrade` | Execute software updates |
4. Now enter the first command to fetch update information:
+131 -132
View File
@@ -6,8 +6,8 @@ Security protection for Linux servers is a vast and complex topic. Countless web
Now that you own a VPS and will be opening up its data access channels to achieve traffic forwarding, you have effectively placed yourself on the front lines of this security battlefield, facing all risks directly. However, due to a lack of knowledge and information, newcomers often view security issues with polarized attitudes: they either feel it's trivial and has nothing to do with them, or they feel the weight is unbearable and live in constant fear.
* **For the former**, my advice is: No security matter is too small. Try to research security information as much as possible to avoid regretting it only after you have suffered a loss.
* **For the latter**, my advice is: Don't panic. Our servers generally don't hold high value and won't attract high-level targeted attacks. We mostly face malicious scanning and login attempts by automated scripts. Just follow this article to implement basic protections.
- **For the former**, my advice is: No security matter is too small. Try to research security information as much as possible to avoid regretting it only after you have suffered a loss.
- **For the latter**, my advice is: Don't panic. Our servers generally don't hold high value and won't attract high-level targeted attacks. We mostly face malicious scanning and login attempts by automated scripts. Just follow this article to implement basic protections.
## 4.2 What Exactly Are the Specific Risks?
@@ -17,13 +17,13 @@ Just as we configured in the "Remote Login" chapter, anyone only needs to know f
2. **[Port]**: If using the default port, then **[Port = `22`]**.
3. **[Username]**: If using the default user, then **[Username = `root`]**.
4. **[Password]**: There is no default password; it is definitely randomly generated by the VPS backend or set by you. This means if your server uses default settings, three of the four elements are already known. The security of your entire server relies entirely on a small string of passwords. Here are a few scenarios:
* If you use the random password generated by the VPS panel, it usually contains a dozen mixed-case letters and symbols, which is relatively safe.
* If, for the sake of memory, you changed the password to something ultra-weak like `123456`, cracking your VPS server would be effortless.
* If, for the sake of memory, you changed the password to something complex but used elsewhere, it is essentially unsafe. You must understand that hackers have "cheat sheets," such as **Password Dictionaries**, containing tens of thousands to millions of leaked real passwords.
- If you use the random password generated by the VPS panel, it usually contains a dozen mixed-case letters and symbols, which is relatively safe.
- If, for the sake of memory, you changed the password to something ultra-weak like `123456`, cracking your VPS server would be effortless.
- If, for the sake of memory, you changed the password to something complex but used elsewhere, it is essentially unsafe. You must understand that hackers have "cheat sheets," such as **Password Dictionaries**, containing tens of thousands to millions of leaked real passwords.
5. **But you must understand**, no hacker is actually sitting in front of a computer trying your password one by one. All attack attempts are carried out automatically by malicious scripts working 24/7. Perhaps while you are sound asleep, your server is enduring round after round of impacts.
Once the password is successfully brute-forced, it means all your four elements are mastered by the attacker. The malicious script will quickly log in, obtain the highest `root` control of the server, install/deploy its malicious services, and then use your server to do various bad things 24 hours a day (such as mining, spreading viruses, sending spam/phishing emails, acting as a BT relay, or even becoming a public node for the dark web, etc.). If the malicious script is restrained, it can be quite stealthy. Since newcomers generally don't observe VPS login records, process changes, CPU usage, or traffic changes, it is difficult to discover that you have been hacked until your VPS provider bans your account or you receive a lawyer's letter.
Once the password is successfully brute-forced, it means all your four elements are mastered by the attacker. The malicious script will quickly log in, obtain the highest `root` control of the server, install/deploy its malicious services, and then use your server to do various bad things 24 hours a day (such as mining, spreading viruses, sending spam/phishing emails, acting as a BT relay, or even becoming a public node for the dark web, etc.). If the malicious script is restrained, it can be quite stealthy. Since newcomers generally don't observe VPS login records, process changes, CPU usage, or traffic changes, it is difficult to discover that you have been hacked until your VPS provider bans your account or you receive a lawyer's letter.
6. **Don't forget**, you likely used real payment information to obtain the VPS, and you leave your IP address when logging into various websites and social platforms. These are directly or indirectly related to your identity. **Once these bad things happen, they will inevitably be linked to you.**
@@ -43,61 +43,61 @@ Now, let's solve the **[Port = `22`]** issue. (Note: Some VPS providers already
1. **Newbie Linux Basic Commands:**
| ID | Command Name | Command Description |
| :---: | :---: | :---: |
| `cmd-03` | `nano` | Text Editor |
| `cmd-04` | `systemctl restart` | Restart a specific service |
| ID | Command Name | Command Description |
| :------: | :-----------------: | :------------------------: |
| `cmd-03` | `nano` | Text Editor |
| `cmd-04` | `systemctl restart` | Restart a specific service |
2. **Newbie Linux Basic Configuration Files:**
| ID | Config File Location | File Description |
| :---: | :---: | :---: |
| `conf-01` | `/etc/ssh/sshd_config` | SSH Remote Login Program Settings |
| ID | Config File Location | File Description |
| :-------: | :--------------------: | :-------------------------------: |
| `conf-01` | `/etc/ssh/sshd_config` | SSH Remote Login Program Settings |
3. The first thing we need to do is **[Use the `nano` text editor to open the `SSH Remote Login Program Settings`]**. In Windows, you would "find the file and double-click it." What about in Linux? Look at the command description above; isn't it simple? That's right, it is:
```shell
nano /etc/ssh/sshd_config
```
```shell
nano /etc/ssh/sshd_config
```
4. After the file opens, you enter the `nano` interface. Observe briefly, and you'll find that it displays important shortcut keys at the bottom of the screen (in the red box below). It's like an open-book exam; no need for rote memorization. Isn't that thoughtful?
![nano interface](./ch04-img01-nano-ui.png)
![nano interface](./ch04-img01-nano-ui.png)
5. The second thing we need to do is **[Find `Port` in the opened file and modify its port number]**. The number after `Port` is the SSH port. It is generally recommended to change it to an integer greater than `1024` and less than `65535` (this article uses `9753` as an example). Combining with `nano` shortcuts, how should we operate? As expected, you got it right again!
* Use `ctrl+w` to enter search mode, then type `Port 22` and hit Enter.
* Delete `22` and change it to `9753`.
* **Note:** If the line starts with a `#`, it means this line is **[Not Effective]** (commented out). You can write a new one without `#` at the end of the file like I did, or just delete the `#`.
- Use `ctrl+w` to enter search mode, then type `Port 22` and hit Enter.
- Delete `22` and change it to `9753`.
- **Note:** If the line starts with a `#`, it means this line is **[Not Effective]** (commented out). You can write a new one without `#` at the end of the file like I did, or just delete the `#`.
::: warning
Using `9753` as an example in this article means that with the release of this article, this port will become a minor characteristic. It might be prioritized by attackers or interfered with/blocked by the GFW. Therefore, I strongly suggest you use a different port number you come up with yourself. After all, you have over 60,000 ports to choose from freely.
:::
::: warning
Using `9753` as an example in this article means that with the release of this article, this port will become a minor characteristic. It might be prioritized by attackers or interfered with/blocked by the GFW. Therefore, I strongly suggest you use a different port number you come up with yourself. After all, you have over 60,000 ports to choose from freely.
:::
6. The third thing we need to do is **[Save the file and exit]**.
* If you observed carefully in step 3, you'd notice that save isn't the common `ctrl+s`.
* **Correct Shortcuts:** Save is `ctrl+o` + `Enter`, Exit is `ctrl+x`.
* **(Some Operating Systems)** Add a firewall rule for the new SSH port; otherwise, you won't be able to login via SSH after the instance restarts.
* Example for Ubuntu `ufw`:
- If you observed carefully in step 3, you'd notice that save isn't the common `ctrl+s`.
- **Correct Shortcuts:** Save is `ctrl+o` + `Enter`, Exit is `ctrl+x`.
- **(Some Operating Systems)** Add a firewall rule for the new SSH port; otherwise, you won't be able to login via SSH after the instance restarts.
- Example for Ubuntu `ufw`:
```shell
sudo ufw allow 9753/tcp
```
```shell
sudo ufw allow 9753/tcp
```
7. The final thing to do is **[Restart the SSH service to make changes take effect]**:
```shell
systemctl restart ssh
```
```shell
systemctl restart ssh
```
*Then try to open a new session in your SSH software to see if you can connect. If there are issues, you can modify the configuration via the old SSH session (the SSH session that was already open when sshd restarted will not be closed).*
_Then try to open a new session in your SSH software to see if you can connect. If there are issues, you can modify the configuration via the old SSH session (the SSH session that was already open when sshd restarted will not be closed)._
8. Full process demonstration:
![Changing port demonstration](./ch04-img02-sshd-conf-full.gif)
![Changing port demonstration](./ch04-img02-sshd-conf-full.gif)
9. **Modify PuTTY Configuration**
Now that the new port is effective, you must use `9753` the next time you log in with PuTTY. So, please go to PuTTY settings, change the port number, and **Save Session**. You know where to change it, right? (If not, re-read the previous content!)
Now that the new port is effective, you must use `9753` the next time you log in with PuTTY. So, please go to PuTTY settings, change the port number, and **Save Session**. You know where to change it, right? (If not, re-read the previous content!)
## 4.5 Create a Non-root New User
@@ -107,85 +107,85 @@ First, you need to understand that `root` in a Linux system is not just a simple
1. **Newbie Linux Basic Commands:**
| ID | Command Name | Command Description |
| :---: | :---: | :---: |
| `cmd-05` | `adduser` | Add a user to the system |
| `cmd-06` | `apt install` | Install specific software |
| `cmd-07` | `visudo` | Dedicated editor for modifying sudo permissions |
| ID | Command Name | Command Description |
| :------: | :-----------: | :---------------------------------------------: |
| `cmd-05` | `adduser` | Add a user to the system |
| `cmd-06` | `apt install` | Install specific software |
| `cmd-07` | `visudo` | Dedicated editor for modifying sudo permissions |
2. The first thing to do is **[Add a new user and set a login password]**. You can name it whatever you want; I will use `vpsadmin` as an example:
```shell
adduser vpsadmin
```
```shell
adduser vpsadmin
```
After executing the command, follow the prompts. **Be sure to set a user password** (don't forget that you won't see `******` when typing the password). Afterward, the system will ask for some additional user info; you can ignore these and just keep hitting Enter.
After executing the command, follow the prompts. **Be sure to set a user password** (don't forget that you won't see `******` when typing the password). Afterward, the system will ask for some additional user info; you can ignore these and just keep hitting Enter.
![Create new user](./ch04-img03-adduser.png)
![Create new user](./ch04-img03-adduser.png)
::: warning
Using `vpsadmin` as an example means this username will also become a minor characteristic upon this article's release. Like the port, I strongly suggest you use a different username you create yourself.
:::
::: warning
Using `vpsadmin` as an example means this username will also become a minor characteristic upon this article's release. Like the port, I strongly suggest you use a different username you create yourself.
:::
3. Full process demonstration:
![Create new user demonstration](./ch04-img04-adduser-full.gif)
![Create new user demonstration](./ch04-img04-adduser-full.gif)
4. The second thing to do is **[Install the `sudo` function]** (`sudo` allows a standard account to temporarily gain the power of `root` at critical moments to save the world).
```shell
apt update && apt install sudo
```
```shell
apt update && apt install sudo
```
Smart users may have noticed this line is actually two commands. The first half `apt update` you've seen and used before; it refreshes software version info. The latter `apt install` is the **[Install Command]**. Joined by `&&`, it means [Refresh available software, AND THEN install the latest version of the `sudo` program].
Smart users may have noticed this line is actually two commands. The first half `apt update` you've seen and used before; it refreshes software version info. The latter `apt install` is the **[Install Command]**. Joined by `&&`, it means [Refresh available software, AND THEN install the latest version of the `sudo` program].
5. The third thing to do is **[Add the `vpsadmin` user to the `sudo` list, granting them eligibility to borrow `root` powers]**.
```shell
visudo
```
```shell
visudo
```
Under `User Privilege Specification`, add a line: `vpsadmin ALL=(ALL) NOPASSWD: ALL`.
Under `User Privilege Specification`, add a line: `vpsadmin ALL=(ALL) NOPASSWD: ALL`.
::: warning
I want to specifically explain the `NOPASSWD` setting. It means the `vpsadmin` user does not need to enter an extra password when using `root` privileges. **This is contrary to general security advice.** The reason I recommend this is that many newcomers ignore danger and persist in using the `root` account simply because they find repeatedly entering passwords annoying. Weighing the lesser of two evils, I believe **[The risk of using the `root` user directly]** is greater than **[The risk of not entering a password when using `sudo`]**, hence the recommendation.
::: warning
I want to specifically explain the `NOPASSWD` setting. It means the `vpsadmin` user does not need to enter an extra password when using `root` privileges. **This is contrary to general security advice.** The reason I recommend this is that many newcomers ignore danger and persist in using the `root` account simply because they find repeatedly entering passwords annoying. Weighing the lesser of two evils, I believe **[The risk of using the `root` user directly]** is greater than **[The risk of not entering a password when using `sudo`]**, hence the recommendation.
If you prefer to follow tradition and enter a password every time you use `sudo`, change that line to `vpsadmin ALL=(ALL:ALL) ALL`.
:::
If you prefer to follow tradition and enter a password every time you use `sudo`, change that line to `vpsadmin ALL=(ALL:ALL) ALL`.
:::
6. Full process demonstration:
![Sudo config demonstration](./ch04-img05-sudo-full.gif)
![Sudo config demonstration](./ch04-img05-sudo-full.gif)
## 4.6 Disable Root SSH Remote Login
1. Now you are getting familiar with Linux, so let's have you think: what is the first thing we need to do? Correct, it is still **[Use the `nano` editor to open `SSH Remote Login Program Settings`]**. What? Can't remember how? Go review the content above and come back! ... Correct Answer:
```shell
nano /etc/ssh/sshd_config
```
```shell
nano /etc/ssh/sshd_config
```
2. Find the `PermitRootLogin Yes` item, and change its setting to `no`. Remember how? ... Correct Answer:
* Use `ctrl+w` to enter search mode, type `PermitRootLogin`, and Enter.
* Delete `yes` and change it to `no`.
- Use `ctrl+w` to enter search mode, type `PermitRootLogin`, and Enter.
- Delete `yes` and change it to `no`.
3. Save the file and exit. Remember how? ... Correct Answer:
* Save is `ctrl+o`, then `Enter` to confirm.
* Exit is `ctrl+x`.
- Save is `ctrl+o`, then `Enter` to confirm.
- Exit is `ctrl+x`.
4. Restart the SSH service to make changes take effect. Remember... Never mind, here is the answer:
```shell
systemctl restart ssh
```
```shell
systemctl restart ssh
```
5. Full process demonstration:
![Disable root login demonstration](./ch04-img06-ssh-no-root-full.gif)
![Disable root login demonstration](./ch04-img06-ssh-no-root-full.gif)
6. Next time you log in via PuTTY, the `root` user will no longer connect; you must switch the username to `vpsadmin`! For convenience, set `vpsadmin` as the default login username in PuTTY. (Nagging Note: Don't forget to Save Session).
![PuTTY default user](./ch04-img07-putty-default-user.png)
![PuTTY default user](./ch04-img07-putty-default-user.png)
## 4.7 Use RSA Key Login and Disable Password Login
@@ -202,9 +202,9 @@ This article uses `RSA` keys as an example because `RSA` has a long history of s
Other common keys include:
* `DSA` - Mathematically proven insecure. Never use it.
* `ECDSA` - Small key size, high security, but its algorithm is suspected of having an NSA backdoor. If you have things on your VPS the NSA cares about, don't use it.
* `Ed25519` - An algorithm very similar to `ECDSA` with similar performance benefits. Its documentation is fully public, so it is generally considered backdoor-free.
- `DSA` - Mathematically proven insecure. Never use it.
- `ECDSA` - Small key size, high security, but its algorithm is suspected of having an NSA backdoor. If you have things on your VPS the NSA cares about, don't use it.
- `Ed25519` - An algorithm very similar to `ECDSA` with similar performance benefits. Its documentation is fully public, so it is generally considered backdoor-free.
Therefore, if your devices and software support it, I recommend prioritizing `Ed25519` keys.
:::
@@ -212,99 +212,98 @@ Therefore, if your devices and software support it, I recommend prioritizing `Ed
Now, let's configure **[Key Authentication]**!
1. Run `PuTTYgen` (PuTTY Key Generator). Location: `Start Menu` --> `All Programs` --> `PuTTY (64-bit)` --> `PuTTYgen`.
1. Click `Generate` to start (move your mouse randomly in the blank area to increase randomness).
1. Click `Generate` to start (move your mouse randomly in the blank area to increase randomness).
![Generate key](./ch04-img08-puttygen-save.png)
![Generate key](./ch04-img08-puttygen-save.png)
::: warning
The image uses a `2048` bit `RSA` key as an example. However, to achieve security equivalent to `ECDSA/Ed25519` `256` bit keys, you need to use a `3072` bit `RSA` key (change the number in the bottom right to `3072`).
:::
::: warning
The image uses a `2048` bit `RSA` key as an example. However, to achieve security equivalent to `ECDSA/Ed25519` `256` bit keys, you need to use a `3072` bit `RSA` key (change the number in the bottom right to `3072`).
:::
1. You can set a password for the private key to add a layer of security.
2. Click `Save public key` to save the public key, name it `id_rsa.pub`.
3. Click `Save private key` to save the private key, name it `id_rsa` (PuTTY private keys come with a `.ppk` extension).
4. **Most Importantly:** Scroll down and copy **all** the content in the red box above, save it as a file named `authorized_keys`. (Saving with vscode might default to a `.txt` extension; that's fine, we will remove the extension when uploading to VPS).
1. You can set a password for the private key to add a layer of security.
2. Click `Save public key` to save the public key, name it `id_rsa.pub`.
3. Click `Save private key` to save the private key, name it `id_rsa` (PuTTY private keys come with a `.ppk` extension).
4. **Most Importantly:** Scroll down and copy **all** the content in the red box above, save it as a file named `authorized_keys`. (Saving with vscode might default to a `.txt` extension; that's fine, we will remove the extension when uploading to VPS).
![Save key content](./ch04-img09-puttygen-save-keys.png)
![Save key content](./ch04-img09-puttygen-save-keys.png)
2. **Upload the public key to the `vpsadmin` user on the VPS.**
1. This step requires `WinSCP` which we prepared earlier.
2. Download and install from the [official site](https://winscp.net/eng/index.php). It will prompt you to import PuTTY settings; do it!
1. This step requires `WinSCP` which we prepared earlier.
2. Download and install from the [official site](https://winscp.net/eng/index.php). It will prompt you to import PuTTY settings; do it!
![Import session](./ch04-img10-winscp-import-session.png)
![Import session](./ch04-img10-winscp-import-session.png)
3. If it doesn't prompt or you installed it earlier, configure it as shown below.
3. If it doesn't prompt or you installed it earlier, configure it as shown below.
![WinSCP login](./ch04-img11-winscp-ui.png)
![WinSCP login](./ch04-img11-winscp-ui.png)
4. The left directory in WinSCP is your local computer; locate the folder where your keys are.
5. The right directory in WinSCP is the VPS. Default is `/home/vpsadmin/`. Click `X hidden` in the bottom right to show hidden files.
4. The left directory in WinSCP is your local computer; locate the folder where your keys are.
5. The right directory in WinSCP is the VPS. Default is `/home/vpsadmin/`. Click `X hidden` in the bottom right to show hidden files.
![Local and Remote folders](./ch04-img12-winscp-locations.png)
![Local and Remote folders](./ch04-img12-winscp-locations.png)
6. Right-click on the right side (VPS) and create a new folder named `.ssh` (Note the dot `.`).
6. Right-click on the right side (VPS) and create a new folder named `.ssh` (Note the dot `.`).
![Create .ssh folder](./ch04-img13-winscp-newfolder-key.png)
![Create .ssh folder](./ch04-img13-winscp-newfolder-key.png)
7. Upload the **[Public Key]** `authorized_keys` into the `.ssh` folder.
7. Upload the **[Public Key]** `authorized_keys` into the `.ssh` folder.
![Upload key](./ch04-img14-winscp-upload-key.png)
![Upload key](./ch04-img14-winscp-upload-key.png)
8. During upload (or after), rename `authorized_keys.txt` to `authorized_keys` (remove the `.txt` extension).
8. During upload (or after), rename `authorized_keys.txt` to `authorized_keys` (remove the `.txt` extension).
![Rename key](./ch04-img15-winscp-rename-key.png)
![Rename key](./ch04-img15-winscp-rename-key.png)
9. Full process demonstration:
9. Full process demonstration:
![WinSCP full demo](./ch04-img16-winscp-full.gif)
![WinSCP full demo](./ch04-img16-winscp-full.gif)
3. **Configure VPS to Enable RSA Key Login and Disable Password Login.**
1. **Newbie Linux Basic Commands:**
1. **Newbie Linux Basic Commands:**
| ID | Command Name | Command Description |
| :---: | :---: | :---: |
| `cmd-08` | `sudo` | Run a command with `root` privileges |
| `cmd-09` | `chmod` | Change permissions of target file/folder |
| ID | Command Name | Command Description |
| :------: | :----------: | :--------------------------------------: |
| `cmd-08` | `sudo` | Run a command with `root` privileges |
| `cmd-09` | `chmod` | Change permissions of target file/folder |
2. Remote SSH into your VPS (PuTTY).
3. Change permissions of `authorized_keys` to `600` (Read/Write for owner only).
2. Remote SSH into your VPS (PuTTY).
3. Change permissions of `authorized_keys` to `600` (Read/Write for owner only).
```shell
chmod 600 ~/.ssh/authorized_keys
```
```shell
chmod 600 ~/.ssh/authorized_keys
```
4. Modify SSH Configuration. We've done this many times, but now we are the normal user `vpsadmin`, not the omnipotent `root`. We don't have permission to edit SSH config directly. We need the `sudo` command:
4. Modify SSH Configuration. We've done this many times, but now we are the normal user `vpsadmin`, not the omnipotent `root`. We don't have permission to edit SSH config directly. We need the `sudo` command:
```shell
sudo nano /etc/ssh/sshd_config
```
```shell
sudo nano /etc/ssh/sshd_config
```
5. Find (`ctrl+w`) `PasswordAuthentication` and change it to `no`.
6. Find (`ctrl+w`) `PubkeyAuthentication` and change it to `yes`. Save (`ctrl+o`) and Exit (`ctrl+x`).
7. Restart SSH service. (Nagging Note: Don't forget you need `sudo` for permission now).
5. Find (`ctrl+w`) `PasswordAuthentication` and change it to `no`.
6. Find (`ctrl+w`) `PubkeyAuthentication` and change it to `yes`. Save (`ctrl+o`) and Exit (`ctrl+x`).
7. Restart SSH service. (Nagging Note: Don't forget you need `sudo` for permission now).
```shell
sudo systemctl restart ssh
```
```shell
sudo systemctl restart ssh
```
8. Full process follows:
8. Full process follows:
![Disable password login full demo](./ch04-img17-rsa-login-full.gif)
![Disable password login full demo](./ch04-img17-rsa-login-full.gif)
4. **Configure PuTTY to use the Private Key.**
The VPS side has the public key. Now specify the private key location for PuTTY to use during login (Nagging Note: Don't forget to Save Session).
The VPS side has the public key. Now specify the private key location for PuTTY to use during login (Nagging Note: Don't forget to Save Session).
![PuTTY private key](./ch04-img18-putty-privatekey-location.png)
![PuTTY private key](./ch04-img18-putty-privatekey-location.png)
5. At this point, **[Key Login]** is enabled, **[Password Authentication]** is disabled, and PuTTY has the default username and private key saved. In the future, just load the `VPS-SERVER` config in PuTTY and click `Open` for one-click login.
If you set a password for your private key, you will need to enter that passphrase to unlock the key when logging in, as shown below:
If you set a password for your private key, you will need to enter that passphrase to unlock the key when logging in, as shown below:
![Private key passphrase](./ch04-img19-putty-privatekey-passphrase.png)
![Private key passphrase](./ch04-img19-putty-privatekey-passphrase.png)
6. Don't forget to configure the key for `WinSCP` as well, otherwise, you won't be able to log in to transfer files later:
![WinSCP private key](./ch04-img20-winscp-privatekey-location.png)
![WinSCP private key](./ch04-img20-winscp-privatekey-location.png)
::: warning
Any software that needs to log in via SSH will now require key authentication. There are too many software options to show individually, so please configure them yourself according to your needs.
+109 -105
View File
@@ -20,153 +20,157 @@ Now for the second question:
1. The commands used here have been explained in detail previously, so they won't be repeated. Students who don't understand can review the previous chapters.
```shell
sudo apt update && sudo apt install nginx
```
```shell
sudo apt update && sudo apt install nginx
```
2. After completion, Nginx runs automatically. Now open a browser on Windows and enter `http://100.200.300.400:80`. If you see the interface below, Nginx is running normally.
![Nginx Default Page](./ch05-img01-nginx-default-running.png)
![Nginx Default Page](./ch05-img01-nginx-default-running.png)
3. If you cannot see the Nginx default page mentioned above, you may need to configure the default firewall component, Uncomplicated Firewall (UFW), on the Debian system to enable HTTP (80) and HTTPS (443) port traffic.
a. Verification method, input:
a. Verification method, input:
```shell
sudo ufw status
```
```shell
sudo ufw status
```
b. If the output is as follows, indicating ports 80 and 443 are not enabled, proceed to step c.
b. If the output is as follows, indicating ports 80 and 443 are not enabled, proceed to step c.
```shell
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
```
```shell
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
```
c. Command to enable Nginx ports 80 and 443 in UFW:
c. Command to enable Nginx ports 80 and 443 in UFW:
```shell
sudo ufw allow 'Nginx Full'
```
```shell
sudo ufw allow 'Nginx Full'
```
d. Enter the command from step a again to verify. If the output is as follows, it means Nginx traffic has been allowed by the firewall, and you should be able to see the Nginx default page mentioned in point 2.
d. Enter the command from step a again to verify. If the output is as follows, it means Nginx traffic has been allowed by the firewall, and you should be able to see the Nginx default page mentioned in point 2.
```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)
```
```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 Create a Very Simple Web Page
1. **Basic Linux Commands for Beginners:**
| Code | Command Name | Description |
| :---: | :---: | :---: |
| `cmd-10` | `mkdir` | Create a new directory |
| `cmd-11` | `systemctl reload` | Reload a service |
| Code | Command Name | Description |
| :------: | :----------------: | :--------------------: |
| `cmd-10` | `mkdir` | Create a new directory |
| `cmd-11` | `systemctl reload` | Reload a service |
2. **Basic Linux Configuration Files for Beginners:**
| Code | File Location | Description |
| :---: | :---: | :---: |
| `conf-02` | `/etc/nginx/nginx.conf` | Nginx program settings |
| Code | File Location | Description |
| :-------: | :---------------------: | :--------------------: |
| `conf-02` | `/etc/nginx/nginx.conf` | Nginx program settings |
3. Create a dedicated folder for the website `/home/vpsadmin/www/webpage/` and create the webpage file `index.html`.
```shell
mkdir -p ~/www/webpage/ && nano ~/www/webpage/index.html
```
```shell
mkdir -p ~/www/webpage/ && nano ~/www/webpage/index.html
```
::: warning
If you are not using the username `vpsadmin`, please understand the meaning of the `“~”` symbol in this command (this relates to the content you will write in [Step 5]):
- If you are a [non-root user], `“~”` is equivalent to `/home/username`.
- If you are the [root user], `“~”` is equivalent to `/root`.
:::
::: warning
If you are not using the username `vpsadmin`, please understand the meaning of the `“~”` symbol in this command (this relates to the content you will write in [Step 5]):
- If you are a [non-root user], `“~”` is equivalent to `/home/username`.
- If you are the [root user], `“~”` is equivalent to `/root`.
:::
4. Copy the content below completely into the file, then save (`ctrl+o`) and exit (`ctrl+x`).
```html
<html lang="">
<head>
<title>Enter a title, displayed at the top of the window.</title>
</head>
<body>
<h1>Enter the main heading, usually the same as the title.</h1>
<p>Be <b>bold</b> in stating your key points. Put them in a list:</p>
<ul>
<li>The first item in your list</li>
<li>The second item; <i>italicize</i> key words</li>
</ul>
<p>Improve your image by including an image.</p>
<p>
<img src="[https://i.imgur.com/SEBww.jpg](https://i.imgur.com/SEBww.jpg)" alt="A Great HTML Resource" />
</p>
<p>
Add a link to your favorite
<a href="[https://www.dummies.com/](https://www.dummies.com/)">Web site</a>. Break up your page
with a horizontal rule or two.
</p>
<hr />
<p>
Finally, link to <a href="page2.html">another page</a> in your own Web
site.
</p>
<p>&#169; Wiley Publishing, 2011</p>
</body>
</html>
```
```html
<html lang="">
<head>
<title>Enter a title, displayed at the top of the window.</title>
</head>
<body>
<h1>Enter the main heading, usually the same as the title.</h1>
<p>
Be <b>bold</b> in stating your key points. Put them in a list:
</p>
<ul>
<li>The first item in your list</li>
<li>The second item; <i>italicize</i> key words</li>
</ul>
<p>Improve your image by including an image.</p>
<p>
<img
src="[https://i.imgur.com/SEBww.jpg](https://i.imgur.com/SEBww.jpg)"
alt="A Great HTML Resource"
/>
</p>
<p>
Add a link to your favorite
<a href="[https://www.dummies.com/](https://www.dummies.com/)"
>Web site</a
>. Break up your page with a horizontal rule or two.
</p>
<hr />
<p>
Finally, link to <a href="page2.html">another page</a> in your own
Web site.
</p>
<p>&#169; Wiley Publishing, 2011</p>
</body>
</html>
```
Grant read permissions to other users for this file:
Grant read permissions to other users for this file:
```shell
chmod -R a+r .
```
```shell
chmod -R a+r .
```
5. Modify `nginx.conf` and restart the `Nginx` service to point http access on port `80` to the `html` page just created.
1. Modify `nginx.conf`.
1. Modify `nginx.conf`.
```shell
sudo nano /etc/nginx/nginx.conf
```
```shell
sudo nano /etc/nginx/nginx.conf
```
2. Add the following segment inside `http{}`, then save (`ctrl+o`) and exit (`ctrl+x`). (Remember to replace the domain name with the real domain name including the subdomain you prepared earlier).
2. Add the following segment inside `http{}`, then save (`ctrl+o`) and exit (`ctrl+x`). (Remember to replace the domain name with the real domain name including the subdomain you prepared earlier).
```nginx
server {
listen 80;
server_name subdomain.yourdomain.com;
root /home/vpsadmin/www/webpage;
index index.html;
}
```
```nginx
server {
listen 80;
server_name subdomain.yourdomain.com;
root /home/vpsadmin/www/webpage;
index index.html;
}
```
::: warning Special Note!
As mentioned in my hint in [Step 3], please make sure `/home/vpsadmin/www/webpage` is changed to your actual file path.
:::
::: warning Special Note!
As mentioned in my hint in [Step 3], please make sure `/home/vpsadmin/www/webpage` is changed to your actual file path.
:::
3. Reload the `nginx` configuration to make it effective.
3. Reload the `nginx` configuration to make it effective.
```shell
sudo systemctl reload nginx
```
```shell
sudo systemctl reload nginx
```
4. The complete setup process is shown below:
4. The complete setup process is shown below:
![Webpage Setup Demo](./ch05-img02-nginx-conf-full.gif)
![Webpage Setup Demo](./ch05-img02-nginx-conf-full.gif)
5. Now, if you visit `http://subdomain.yourdomain.com` and see a page like this, it means success:
5. Now, if you visit `http://subdomain.yourdomain.com` and see a page like this, it means success:
![HTTP Webpage Success](./ch05-img03-nginx-http-running.png)
![HTTP Webpage Success](./ch05-img03-nginx-http-running.png)
## 5.4 Explanation of Common Errors
+101 -101
View File
@@ -16,32 +16,32 @@ Additionally, I trust that by now you are gradually becoming familiar with basic
1. Basic Linux Commands for Beginners:
| ID | Command | Description |
|:--:|:--:|:--:|
| `cmd-12` | `wget` | Visit (or download) a web file |
| `cmd-13` | `acme.sh` | Commands related to acme.sh certificate management |
| ID | Command | Description |
| :------: | :-------: | :------------------------------------------------: |
| `cmd-12` | `wget` | Visit (or download) a web file |
| `cmd-13` | `acme.sh` | Commands related to acme.sh certificate management |
2. Run the installation script
```shell
wget -O - [https://get.acme.sh](https://get.acme.sh) | sh
```
```shell
wget -O - [https://get.acme.sh](https://get.acme.sh) | sh
```
3. Make the `acme.sh` command effective
```shell
. .bashrc
```
```shell
. .bashrc
```
4. Enable auto-upgrade for `acme.sh`
```shell
acme.sh --upgrade --auto-upgrade
```
```shell
acme.sh --upgrade --auto-upgrade
```
5. The complete process up to this step is shown below:
![acme.sh installation demo](./ch06-img01-acme-install.gif)
![acme.sh installation demo](./ch06-img01-acme-install.gif)
## 6.3 Testing Certificate Issuance
@@ -49,61 +49,61 @@ Before officially applying for a certificate, let's use a test command (`--issue
1. The command to test certificate issuance is as follows (This article uses `ECC` certificates as an example, because nowadays, there is really no reason not to use them):
```shell
acme.sh --issue --server letsencrypt_test -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256
```
```shell
acme.sh --issue --server letsencrypt_test -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256
```
::: warning Note
The main advantage of `ECC` certificates lies in their smaller Key size, which means improved security and faster encryption/decryption speeds for the same size. For instance, the strength of ECC-256bit is roughly equivalent to RSA-3072bit, so why not? Of course, some say ECC certificate handshakes are noticeably faster; I think that's a bit of an exaggeration. RSA handshakes aren't that slow, and even if there is a difference, it should be in milliseconds, which is hard to perceive directly.
::: warning Note
The main advantage of `ECC` certificates lies in their smaller Key size, which means improved security and faster encryption/decryption speeds for the same size. For instance, the strength of ECC-256bit is roughly equivalent to RSA-3072bit, so why not? Of course, some say ECC certificate handshakes are noticeably faster; I think that's a bit of an exaggeration. RSA handshakes aren't that slow, and even if there is a difference, it should be in milliseconds, which is hard to perceive directly.
However, if some websites specifically need to be compatible with very ancient devices, please choose `RSA` certificates as needed.
:::
However, if some websites specifically need to be compatible with very ancient devices, please choose `RSA` certificates as needed.
:::
2. You should ultimately see a log similar to this:
```log
[Wed 30 Dec 2022 04:25:12 AM EST] Using ACME_DIRECTORY: [https://acme-staging-v02.api.letsencrypt.org/directory](https://acme-staging-v02.api.letsencrypt.org/directory)
[Wed 30 Dec 2022 04:25:13 AM EST] Using CA: [https://acme-staging-v02.api.letsencrypt.org/directory](https://acme-staging-v02.api.letsencrypt.org/directory)
[Wed 30 Dec 2022 04:25:13 AM EST] Create account key ok.
[Wed 30 Dec 2022 04:25:13 AM EST] Registering account: [https://acme-staging-v02.api.letsencrypt.org/directory](https://acme-staging-v02.api.letsencrypt.org/directory)
[Wed 30 Dec 2022 04:25:13 AM EST] Registered
[Wed 30 Dec 2022 04:25:13 AM EST] ACCOUNT_THUMBPRINT='CU6qmPKuRqhyTAIrF4swosR375194z_1ddUlWef8xDc'
[Wed 30 Dec 2022 04:25:13 AM EST] Creating domain key
[Wed 30 Dec 2022 04:25:13 AM EST] The domain key is here: /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.key
[Wed 30 Dec 2022 04:25:13 AM EST] Single domain='subdomain.yourdomain.com'
[Wed 30 Dec 2022 04:25:13 AM EST] Getting domain auth token for each domain
[Wed 30 Dec 2022 04:25:14 AM EST] Getting webroot for domain='subdomain.yourdomain.com'
[Wed 30 Dec 2022 04:25:14 AM EST] Verifying: subdomain.yourdomain.com
[Wed 30 Dec 2022 04:25:23 AM EST] Pending
[Wed 30 Dec 2022 04:25:25 AM EST] Success
[Wed 30 Dec 2022 04:25:25 AM EST] Verify finished, start to sign.
[Wed 30 Dec 2022 04:25:25 AM EST] Lets finalize the order.
[Wed 30 Dec 2022 04:25:25 AM EST] Le_OrderFinalize='[https://acme-staging-v02.api.letsencrypt.org/acme/finalize/490205995/7730242871](https://acme-staging-v02.api.letsencrypt.org/acme/finalize/490205995/7730242871)'
[Wed 30 Dec 2022 04:25:25 AM EST] Downloading cert.
[Wed 30 Dec 2022 04:25:25 AM EST] Le_LinkCert='[https://acme-staging-v02.api.letsencrypt.org/acme/cert/xujss5xt8i38waubafz2xujss5xt8i38waubz2](https://acme-staging-v02.api.letsencrypt.org/acme/cert/xujss5xt8i38waubafz2xujss5xt8i38waubz2)'
[Wed 30 Dec 2022 15:21:52 AM EST] Cert success.
--BEGIN CERTIFICAT--
sxlYqPvWreKgD5b8JyOQX0Yg2MLoRUoDyqVkd31PthIiwzdckoh5eD3JU7ysYBtN
cTFK4LGOfjqi8Ks87EVJdK9IaSAu7ZC6h5to0eqpJ5PLhaM3e6yJBbHmYA8w1Smp
wAb3tdoHZ9ttUIm9CrSzvDBt6BBT6GqYdDamMyCYBLooMyDEM4CUFsOzCRrEqqvC
... (omitted for brevity) ...
yiLKcBFc5H7dgJCImo7us7aJeftC44uWkPIjw9AKH=
--END CERTIFICAT--
[Wed 30 Dec 2022 15:21:52 AM EST] Your cert is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.cer
[Wed 30 Dec 2022 15:21:52 AM EST] Your cert key is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.key
[Wed 30 Dec 2022 15:21:52 AM EST] The intermediate CA cert is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/ca.cer
[Wed 30 Dec 2022 15:21:52 AM EST] And the full chain certs is there: /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/fullchain.cer
```
```log
[Wed 30 Dec 2022 04:25:12 AM EST] Using ACME_DIRECTORY: [https://acme-staging-v02.api.letsencrypt.org/directory](https://acme-staging-v02.api.letsencrypt.org/directory)
[Wed 30 Dec 2022 04:25:13 AM EST] Using CA: [https://acme-staging-v02.api.letsencrypt.org/directory](https://acme-staging-v02.api.letsencrypt.org/directory)
[Wed 30 Dec 2022 04:25:13 AM EST] Create account key ok.
[Wed 30 Dec 2022 04:25:13 AM EST] Registering account: [https://acme-staging-v02.api.letsencrypt.org/directory](https://acme-staging-v02.api.letsencrypt.org/directory)
[Wed 30 Dec 2022 04:25:13 AM EST] Registered
[Wed 30 Dec 2022 04:25:13 AM EST] ACCOUNT_THUMBPRINT='CU6qmPKuRqhyTAIrF4swosR375194z_1ddUlWef8xDc'
[Wed 30 Dec 2022 04:25:13 AM EST] Creating domain key
[Wed 30 Dec 2022 04:25:13 AM EST] The domain key is here: /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.key
[Wed 30 Dec 2022 04:25:13 AM EST] Single domain='subdomain.yourdomain.com'
[Wed 30 Dec 2022 04:25:13 AM EST] Getting domain auth token for each domain
[Wed 30 Dec 2022 04:25:14 AM EST] Getting webroot for domain='subdomain.yourdomain.com'
[Wed 30 Dec 2022 04:25:14 AM EST] Verifying: subdomain.yourdomain.com
[Wed 30 Dec 2022 04:25:23 AM EST] Pending
[Wed 30 Dec 2022 04:25:25 AM EST] Success
[Wed 30 Dec 2022 04:25:25 AM EST] Verify finished, start to sign.
[Wed 30 Dec 2022 04:25:25 AM EST] Lets finalize the order.
[Wed 30 Dec 2022 04:25:25 AM EST] Le_OrderFinalize='[https://acme-staging-v02.api.letsencrypt.org/acme/finalize/490205995/7730242871](https://acme-staging-v02.api.letsencrypt.org/acme/finalize/490205995/7730242871)'
[Wed 30 Dec 2022 04:25:25 AM EST] Downloading cert.
[Wed 30 Dec 2022 04:25:25 AM EST] Le_LinkCert='[https://acme-staging-v02.api.letsencrypt.org/acme/cert/xujss5xt8i38waubafz2xujss5xt8i38waubz2](https://acme-staging-v02.api.letsencrypt.org/acme/cert/xujss5xt8i38waubafz2xujss5xt8i38waubz2)'
[Wed 30 Dec 2022 15:21:52 AM EST] Cert success.
--BEGIN CERTIFICAT--
sxlYqPvWreKgD5b8JyOQX0Yg2MLoRUoDyqVkd31PthIiwzdckoh5eD3JU7ysYBtN
cTFK4LGOfjqi8Ks87EVJdK9IaSAu7ZC6h5to0eqpJ5PLhaM3e6yJBbHmYA8w1Smp
wAb3tdoHZ9ttUIm9CrSzvDBt6BBT6GqYdDamMyCYBLooMyDEM4CUFsOzCRrEqqvC
... (omitted for brevity) ...
yiLKcBFc5H7dgJCImo7us7aJeftC44uWkPIjw9AKH=
--END CERTIFICAT--
[Wed 30 Dec 2022 15:21:52 AM EST] Your cert is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.cer
[Wed 30 Dec 2022 15:21:52 AM EST] Your cert key is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.key
[Wed 30 Dec 2022 15:21:52 AM EST] The intermediate CA cert is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/ca.cer
[Wed 30 Dec 2022 15:21:52 AM EST] And the full chain certs is there: /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/fullchain.cer
```
3. Note: What we applied for here is a test certificate. It cannot be used directly; it merely proves that your domain and configuration are all correct. Look closely, and you will find that the issuer domain is `https://acme-staging-v02.api.letsencrypt.org`. You can understand this `staging` as the "Test Server"!
4. If an error occurs in this step, you can run the following command to view the detailed application process and specific errors. (If you don't understand it, hide sensitive information and ask in the Xray community group).
```shell
acme.sh --issue --server letsencrypt_test -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256 --debug
```
```shell
acme.sh --issue --server letsencrypt_test -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256 --debug
```
Yes, that's right, just add a `--debug` parameter at the end of the command.
Yes, that's right, just add a `--debug` parameter at the end of the command.
5. After confirming this step is successful, you can apply for the official certificate. (You don't need to delete the test certificate; it will be automatically overwritten by the official certificate).
@@ -111,48 +111,48 @@ Before officially applying for a certificate, let's use a test command (`--issue
1. The command to apply for the official certificate is as follows (change the `--server letsencrypt_test` parameter to `--server letsencrypt`, and add the `--force` parameter at the end):
```shell
acme.sh --set-default-ca --server letsencrypt
```
```shell
acme.sh --set-default-ca --server letsencrypt
```
```shell
acme.sh --issue -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256 --force
```
```shell
acme.sh --issue -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256 --force
```
::: warning Note
The `--force` parameter means to manually (forcefully) update the certificate before the existing certificate expires. Although the certificate we applied for from the "Test Server" in the previous step cannot be used directly, it has not yet expired, so this parameter is needed.
:::
::: warning Note
The `--force` parameter means to manually (forcefully) update the certificate before the existing certificate expires. Although the certificate we applied for from the "Test Server" in the previous step cannot be used directly, it has not yet expired, so this parameter is needed.
:::
2. You should ultimately see a log very similar to the one above:
```log
vpsadmin@vps-server:~$ acme.sh --issue -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256
[Wed 30 Dec 2022 15:22:51 AM EST] Using CA: [https://acme-v02.api.letsencrypt.org/directory](https://acme-v02.api.letsencrypt.org/directory)
[Wed 30 Dec 2022 15:22:51 AM EST] Creating domain key
[Wed 30 Dec 2022 15:22:51 AM EST] The domain key is here: /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.key
[Wed 30 Dec 2022 15:22:51 AM EST] Single domain='subdomain.yourdomain.com'
[Wed 30 Dec 2022 15:22:51 AM EST] Getting domain auth token for each domain
[Wed 30 Dec 2022 15:22:51 AM EST] Getting webroot for domain='subdomain.yourdomain.com'
[Wed 30 Dec 2022 15:22:51 AM EST] Verifying: subdomain.yourdomain.com
[Wed 30 Dec 2022 15:22:51 AM EST] Pending
[Wed 30 Dec 2022 15:22:51 AM EST] Success
[Wed 30 Dec 2022 15:22:51 AM EST] Verify finished, start to sign.
[Wed 30 Dec 2022 15:22:51 AM EST] Lets finalize the order.
[Wed 30 Dec 2022 15:22:51 AM EST] Le_OrderFinalize='[https://acme-v02.api.letsencrypt.org/acme/finalize/490205996/7730242872](https://acme-v02.api.letsencrypt.org/acme/finalize/490205996/7730242872)'
[Wed 30 Dec 2022 15:22:51 AM EST] Downloading cert.
[Wed 30 Dec 2022 15:22:51 AM EST] Le_LinkCert='[https://acme-v02.api.letsencrypt.org/acme/cert/vsxvk0oldnuobe51ayxz4dms62sk2dwmw9zhuw](https://acme-v02.api.letsencrypt.org/acme/cert/vsxvk0oldnuobe51ayxz4dms62sk2dwmw9zhuw)'
[Wed 30 Dec 2022 15:22:51 AM EST] Cert success.
--BEGIN CERTIFICAT--
sxlYqPvWreKgD5b8JyOQX0Yg2MLoRUoDyqVkd31PthIiwzdckoh5eD3JU7ysYBtN
cTFK4LGOfjqi8Ks87EVJdK9IaSAu7ZC6h5to0eqpJ5PLhaM3e6yJBbHmYA8w1Smp
... (omitted for brevity) ...
yiLKcBFc5H7dgJCImo7us7aJeftC44uWkPM=
--END CERTIFICAT--
[Wed 30 Dec 2022 15:22:52 AM EST] Your cert is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.cer
[Wed 30 Dec 2022 15:22:52 AM EST] Your cert key is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.key
[Wed 30 Dec 2022 15:22:52 AM EST] The intermediate CA cert is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/ca.cer
[Wed 30 Dec 2022 15:22:52 AM EST] And the full chain certs is there: /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/fullchain.cer
```
```log
vpsadmin@vps-server:~$ acme.sh --issue -d subdomain.yourdomain.com -w /home/vpsadmin/www/webpage --keylength ec-256
[Wed 30 Dec 2022 15:22:51 AM EST] Using CA: [https://acme-v02.api.letsencrypt.org/directory](https://acme-v02.api.letsencrypt.org/directory)
[Wed 30 Dec 2022 15:22:51 AM EST] Creating domain key
[Wed 30 Dec 2022 15:22:51 AM EST] The domain key is here: /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.key
[Wed 30 Dec 2022 15:22:51 AM EST] Single domain='subdomain.yourdomain.com'
[Wed 30 Dec 2022 15:22:51 AM EST] Getting domain auth token for each domain
[Wed 30 Dec 2022 15:22:51 AM EST] Getting webroot for domain='subdomain.yourdomain.com'
[Wed 30 Dec 2022 15:22:51 AM EST] Verifying: subdomain.yourdomain.com
[Wed 30 Dec 2022 15:22:51 AM EST] Pending
[Wed 30 Dec 2022 15:22:51 AM EST] Success
[Wed 30 Dec 2022 15:22:51 AM EST] Verify finished, start to sign.
[Wed 30 Dec 2022 15:22:51 AM EST] Lets finalize the order.
[Wed 30 Dec 2022 15:22:51 AM EST] Le_OrderFinalize='[https://acme-v02.api.letsencrypt.org/acme/finalize/490205996/7730242872](https://acme-v02.api.letsencrypt.org/acme/finalize/490205996/7730242872)'
[Wed 30 Dec 2022 15:22:51 AM EST] Downloading cert.
[Wed 30 Dec 2022 15:22:51 AM EST] Le_LinkCert='[https://acme-v02.api.letsencrypt.org/acme/cert/vsxvk0oldnuobe51ayxz4dms62sk2dwmw9zhuw](https://acme-v02.api.letsencrypt.org/acme/cert/vsxvk0oldnuobe51ayxz4dms62sk2dwmw9zhuw)'
[Wed 30 Dec 2022 15:22:51 AM EST] Cert success.
--BEGIN CERTIFICAT--
sxlYqPvWreKgD5b8JyOQX0Yg2MLoRUoDyqVkd31PthIiwzdckoh5eD3JU7ysYBtN
cTFK4LGOfjqi8Ks87EVJdK9IaSAu7ZC6h5to0eqpJ5PLhaM3e6yJBbHmYA8w1Smp
... (omitted for brevity) ...
yiLKcBFc5H7dgJCImo7us7aJeftC44uWkPM=
--END CERTIFICAT--
[Wed 30 Dec 2022 15:22:52 AM EST] Your cert is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.cer
[Wed 30 Dec 2022 15:22:52 AM EST] Your cert key is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/subdomain.yourdomain.com.key
[Wed 30 Dec 2022 15:22:52 AM EST] The intermediate CA cert is in /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/ca.cer
[Wed 30 Dec 2022 15:22:52 AM EST] And the full chain certs is there: /home/vpsadmin/.acme.sh/subdomain.yourdomain.com_ecc/fullchain.cer
```
3. Look closely, and you will find that the issuer domain this time is `https://acme-v02.api.letsencrypt.org`. The `staging` is gone, which naturally means it is the "Official Server" (Production)!
@@ -160,12 +160,12 @@ Before officially applying for a certificate, let's use a test command (`--issue
1. After the certificate application is complete, it needs to be installed. Install it to the specified location and reference it in the configuration file:
```shell
vpsadmin@vps-server:~$ acme.sh --installcert -d subdomain.yourdomain.com --cert-file /path/to/installation/cert.crt --key-file /path/to/installation/cert.key --fullchain-file /path/to/installation/fullchain.crt --ecc
[Mon 14 Feb 2022 03:00:25 PM CST] Installing cert to: /etc/xray/cert/cert.crt
[Mon 14 Feb 2022 03:00:25 PM CST] Installing key to: /etc/xray/cert/cert.key
[Mon 14 Feb 2022 03:00:25 PM CST] Installing full chain to: /etc/xray/cert/fullchain.crt
```
```shell
vpsadmin@vps-server:~$ acme.sh --installcert -d subdomain.yourdomain.com --cert-file /path/to/installation/cert.crt --key-file /path/to/installation/cert.key --fullchain-file /path/to/installation/fullchain.crt --ecc
[Mon 14 Feb 2022 03:00:25 PM CST] Installing cert to: /etc/xray/cert/cert.crt
[Mon 14 Feb 2022 03:00:25 PM CST] Installing key to: /etc/xray/cert/cert.key
[Mon 14 Feb 2022 03:00:25 PM CST] Installing full chain to: /etc/xray/cert/fullchain.crt
```
## 6.6 Your Progress
+16 -20
View File
@@ -27,9 +27,9 @@ At the time of writing, the installation script has a few small bugs when using
1. Linux 101 - Basic Commands:
| Number | Command Name | Command Description |
| :---: | :---: | :---: |
| `cmd-14` | `rm` | Delete command |
| Number | Command Name | Command Description |
| :------: | :----------: | :-----------------: |
| `cmd-14` | `rm` | Delete command |
2. Download the installation script locally:
@@ -86,13 +86,11 @@ Although we have already applied for TLS certificates earlier, according to the
![Xray Certificate Install Demo](./ch07-img02-xray-cert-install.png)
5. `acme.sh` checks the certificate every 60 days and automatically renews it if it's close to expiration. However, as far as I know, it does not automatically install the new certificate to `xray-core`, so we need to add a system automatic periodic task to complete this step.
1. Linux 101 - Basic Commands:
| Number | Command Name | Command Description |
| :---: | :---: | :---: |
| Number | Command Name | Command Description |
| :------: | :----------: | :-------------------------------------: |
| `cmd-15` | `crontab -e` | Edit the current user's scheduled tasks |
2. Create a script file (`xray-cert-renew.sh`):
```shell
@@ -156,9 +154,9 @@ First, various configurations can refer to the [official VLESS configuration exa
2. Create log files and folders for later use.
1. Linux 101 - Basic Commands:
| Number | Command Name | Command Description |
| :---: | :---: | :---: |
| `cmd-16` | `touch` | Create a blank file |
| Number | Command Name | Command Description |
| :------: | :----------: | :-----------------: |
| `cmd-16` | `touch` | Create a blank file |
2. Create a [Log Dedicated Folder] inside the `vpsadmin` folder.
@@ -421,7 +419,7 @@ So far, we have used `systemctl` related commands like `start`, `status`, `reloa
To avoid the tragedy of being unable to recognize the kernel, please ensure:
- Take a system snapshot before trying, or
- You have `vnc` to save the situation (and you know how to use it)
:::
:::
10. Modify the `kernel` parameter configuration file `sysctl.conf` and specify enabling `BBR`.
@@ -548,18 +546,16 @@ Congratulations!! At this step, you already possess a server capable of proper s
## 7.11 Important Errata
1. In the first edition, the `Xray` configuration file `config.json` folder location was incorrect. If you operated according to the previous location, `Xray` would not start correctly. Therefore, the correction is explained here. Please check yourself. Sorry for the inconvenience!
- Correct location: `/usr/local/etc/xray/config.json`
- Incorrect location: `/usr/local/etc/config.json`
- Correct location: `/usr/local/etc/xray/config.json`
- Incorrect location: `/usr/local/etc/config.json`
Affected sections:
- 7.4 Configuring `Xray` - 3. Use `nano` to create the `Xray` configuration file
- 7.8 Server Optimization 2 - 6. Modify `Xray`'s fallback settings
- 7.4 Configuring `Xray` - 3. Use `nano` to create the `Xray` configuration file
- 7.8 Server Optimization 2 - 6. Modify `Xray`'s fallback settings
2. In the first edition, when modifying the `Nginx` configuration file `nginx.conf`, the content was incorrect (webpage folder location error). If you operated according to the previous location, `Nginx` would not find the correct website. Please check yourself. Sorry for the inconvenience!
- Correct folder location: `root /home/vpsadmin/www/webpage;`
- Incorrect folder location: `root /var/www/website/html`
- Correct folder location: `root /home/vpsadmin/www/webpage;`
- Incorrect folder location: `root /var/www/website/html`
Affected sections:
- 7.8 Server Optimization 2 - 4. Add a local port listener at the same level as port `80` to provide webpage display
- 7.8 Server Optimization 2 - 4. Add a local port listener at the same level as port `80` to provide webpage display
+18 -18
View File
@@ -11,16 +11,16 @@ The key points are:
1. Apps must, either actively or via a forwarding tool, send data so it **[flows in (`inbounds`)]** to the `Xray` client.
2. After traffic enters the client, it is processed by the **[Client Routing (`routing`)]** according to rules, and then sent to **[flow out (`outbounds`)]** of the `Xray` client in different directions. For example:
1. Domestic traffic connects directly (`direct`).
2. Foreign traffic is forwarded to the VPS (`proxy`).
3. Ad traffic is blocked (`block`).
1. Domestic traffic connects directly (`direct`).
2. Foreign traffic is forwarded to the VPS (`proxy`).
3. Ad traffic is blocked (`block`).
3. Foreign traffic forwarded to the VPS will cross the firewall and **[flow in (`inbounds`)]** to the `Xray` server-side.
4. After traffic enters the server-side, just like on the client, it is processed by the **[Server Routing (`routing`)]** according to rules, and then sent to **[flow out (`outbounds`)]** in different directions:
1. Since it is already outside the firewall, traffic connects directly by default, allowing you to access those "non-existent" websites (`direct`).
2. If you need to perform chained forwarding between different VPSs, you can continue to configure forwarding rules (`proxy`).
3. You can continue to disable various traffic you want to ban on the server side, such as ads, BitTorrent downloads, etc. (`block`).
1. Since it is already outside the firewall, traffic connects directly by default, allowing you to access those "non-existent" websites (`direct`).
2. If you need to perform chained forwarding between different VPSs, you can continue to configure forwarding rules (`proxy`).
3. You can continue to disable various traffic you want to ban on the server side, such as ads, BitTorrent downloads, etc. (`block`).
:::warning Note
@@ -258,23 +258,23 @@ Secondly, what we need to do is [make `xray` find and read the configuration fil
1. On Windows, assuming your `Xray` program location is `C:\Xray-windows-64\xray.exe` and the configuration file location is `C:\Xray-windows-64\config.json`, the correct startup command is:
```shell
C:\Xray-windows-64\xray.exe -c C:\Xray-windows-64\config.json
```
```shell
C:\Xray-windows-64\xray.exe -c C:\Xray-windows-64\config.json
```
:::tip Explanation
The `-c` here is the parameter to specify the configuration file path, telling `xray` to look for the configuration file at the location following it.
:::
:::tip Explanation
The `-c` here is the parameter to specify the configuration file path, telling `xray` to look for the configuration file at the location following it.
:::
2. Similarly, on Linux and macOS, assuming your `Xray` program location is `/usr/local/bin/xray` and the configuration file location is `/usr/local/etc/xray/config.json`, the correct startup command is:
```shell
/usr/local/bin/xray -c /usr/local/etc/xray/config.json
```
```shell
/usr/local/bin/xray -c /usr/local/etc/xray/config.json
```
:::tip Explanation
Every system has system path variables, so you don't necessarily have to write the absolute path when typing the `Xray` program. But writing it is definitely not wrong, so I demonstrated it that way.
:::
:::tip Explanation
Every system has system path variables, so you don't necessarily have to write the absolute path when typing the `Xray` program. But writing it is definitely not wrong, so I demonstrated it that way.
:::
## 8.5 Bonus Task 3: Auto-start `xray-core` on PC Boot
+35 -35
View File
@@ -2,45 +2,45 @@
## 1. Index of Basic Linux Commands for Beginners
| ID | Command Name | Description | Featured Chapter |
| :----: | :------------------ | :--------------------------- | :------------------------------------------: |
| `cmd-01` | `apt update` | Check for software updates | [[Chapter 3: Remote Login]](./ch03-ssh.md) |
| `cmd-02` | `apt upgrade` | Execute software updates | [[Chapter 3: Remote Login]](./ch03-ssh.md) |
| `cmd-03` | `nano` | Text editor | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-04` | `systemctl restart` | Restart a service | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-05` | `adduser` | Add a new user to the system | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-06` | `apt install` | Install a software package | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-07` | `visudo` | Dedicated editor for sudo privileges | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-08` | `sudo` | Run a command with `root` privileges | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-09` | `chmod` | Change permissions of a file/folder | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-10` | `mkdir` | Create a new directory (folder) | [[Chapter 5: Website Building]](./ch05-webpage.md) |
| `cmd-11` | `systemctl reload` | Reload a service | [[Chapter 5: Website Building]](./ch05-webpage.md) |
| `cmd-12` | `wget` | Access (or download) a web file | [[Chapter 6: Certificate Management]](./ch06-certificates.md) |
| `cmd-13` | `acme.sh` | Commands related to acme.sh certificate management | [[Chapter 6: Certificate Management]](./ch06-certificates.md) |
| `cmd-14` | `rm` | Remove (delete) command | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `cmd-15` | `crontab -e` | Edit current user's scheduled tasks | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `cmd-16` | `touch` | Create an empty file | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `cmd-17` | `systemctl` | Basic `systemd` service management command | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `cmd-18` | `reboot` | Reboot the Linux system | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| ID | Command Name | Description | Featured Chapter |
| :------: | :------------------ | :------------------------------------------------- | :-----------------------------------------------------------: |
| `cmd-01` | `apt update` | Check for software updates | [[Chapter 3: Remote Login]](./ch03-ssh.md) |
| `cmd-02` | `apt upgrade` | Execute software updates | [[Chapter 3: Remote Login]](./ch03-ssh.md) |
| `cmd-03` | `nano` | Text editor | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-04` | `systemctl restart` | Restart a service | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-05` | `adduser` | Add a new user to the system | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-06` | `apt install` | Install a software package | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-07` | `visudo` | Dedicated editor for sudo privileges | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-08` | `sudo` | Run a command with `root` privileges | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-09` | `chmod` | Change permissions of a file/folder | [[Chapter 4: Security Protection]](./ch04-security.md) |
| `cmd-10` | `mkdir` | Create a new directory (folder) | [[Chapter 5: Website Building]](./ch05-webpage.md) |
| `cmd-11` | `systemctl reload` | Reload a service | [[Chapter 5: Website Building]](./ch05-webpage.md) |
| `cmd-12` | `wget` | Access (or download) a web file | [[Chapter 6: Certificate Management]](./ch06-certificates.md) |
| `cmd-13` | `acme.sh` | Commands related to acme.sh certificate management | [[Chapter 6: Certificate Management]](./ch06-certificates.md) |
| `cmd-14` | `rm` | Remove (delete) command | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `cmd-15` | `crontab -e` | Edit current user's scheduled tasks | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `cmd-16` | `touch` | Create an empty file | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `cmd-17` | `systemctl` | Basic `systemd` service management command | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `cmd-18` | `reboot` | Reboot the Linux system | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
## 2. Index of Important Linux Configuration Files for Beginners
| ID | Config File Location | File Description | Featured Chapter |
| :-------: | :-------------------------------------- | :----------------------------- | :------------------------------------------: |
| `conf-01` | `/etc/ssh/sshd_config` | SSH remote login program settings | [[Chapter 3: Remote Login]](./ch03-ssh.md) |
| `conf-02` | `/etc/nginx/nginx.conf` | Nginx program settings | [[Chapter 5: Website Building]](./ch05-webpage.md) |
| `conf-03` | `/etc/apt/sources.list` | apt software source list | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `conf-04` | `/etc/apt/sources.list.d/vpsadmin.list` | User-defined software source list | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `conf-05` | `crontab -e` | Current user's scheduled tasks | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `conf-06` | `/etc/sysctl.conf` | Manual kernel parameter settings | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `conf-07` | `/etc/sysctl.d/vpsadmin.conf` | User-defined kernel parameter config file | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| ID | Config File Location | File Description | Featured Chapter |
| :-------: | :-------------------------------------- | :---------------------------------------- | :------------------------------------------------: |
| `conf-01` | `/etc/ssh/sshd_config` | SSH remote login program settings | [[Chapter 3: Remote Login]](./ch03-ssh.md) |
| `conf-02` | `/etc/nginx/nginx.conf` | Nginx program settings | [[Chapter 5: Website Building]](./ch05-webpage.md) |
| `conf-03` | `/etc/apt/sources.list` | apt software source list | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `conf-04` | `/etc/apt/sources.list.d/vpsadmin.list` | User-defined software source list | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `conf-05` | `crontab -e` | Current user's scheduled tasks | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `conf-06` | `/etc/sysctl.conf` | Manual kernel parameter settings | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `conf-07` | `/etc/sysctl.d/vpsadmin.conf` | User-defined kernel parameter config file | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
## 3. Index of Important Xray Files for Beginners
| ID | Config File Location | File Description | Featured Chapter |
| :-------: | :----------------------------------- | :--------------- | :------------------------------------------: |
| ID | Config File Location | File Description | Featured Chapter |
| :-------: | :----------------------------------- | :-------------------- | :-----------------------------------------------: |
| `xray-01` | `/usr/local/etc/xray/config.json` | Xray program settings | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `xray-02` | `/home/vpsadmin/xray_cert/xray.cert` | TLS Certificate | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `xray-03` | `/home/vpsadmin/xray_cert/xray.key` | TLS Private Key | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `xray-04` | `/home/vpsadmin/xray_log/access.log` | Xray Access Log | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `xray-05` | `/home/vpsadmin/xray_log/error.log` | Xray Error Log | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `xray-02` | `/home/vpsadmin/xray_cert/xray.cert` | TLS Certificate | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `xray-03` | `/home/vpsadmin/xray_cert/xray.key` | TLS Private Key | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `xray-04` | `/home/vpsadmin/xray_log/access.log` | Xray Access Log | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
| `xray-05` | `/home/vpsadmin/xray_log/error.log` | Xray Error Log | [[Chapter 7: Xray Server]](./ch07-xray-server.md) |
+158 -158
View File
@@ -4,7 +4,7 @@ In the process of using Xray, you must have heard about the **[Fallback]** funct
## 1. Reviewing Fallbacks in the "Beginner's Guide"
If you used the [Xray Configuration](../level-0/ch07-xray-server.md#_7-4-configuration-xray) from the *Beginner's Guide* and completed the [HTTP to HTTPS Redirection Optimization](../level-0/ch07-xray-server.md#_7-8-server-optimization-part-2-enable-http-automatic-jump-to-https), then you already have a simple fallback based on the `VLESS` protocol:
If you used the [Xray Configuration](../level-0/ch07-xray-server.md#_7-4-configuration-xray) from the _Beginner's Guide_ and completed the [HTTP to HTTPS Redirection Optimization](../level-0/ch07-xray-server.md#_7-8-server-optimization-part-2-enable-http-automatic-jump-to-https), then you already have a simple fallback based on the `VLESS` protocol:
```json
{
@@ -35,53 +35,53 @@ How do we explain this configuration in plain language?
1. **Xray's `[inbound port]` is `443`**
This means `Xray` is responsible for listening to `HTTPS` traffic on port `443`.
This means `Xray` is responsible for listening to `HTTPS` traffic on port `443`.
2. **Xray's `[inbound protocol]` is `vless`**
Only traffic using the `vless` protocol will flow into `Xray` for further processing.
Only traffic using the `vless` protocol will flow into `Xray` for further processing.
::: warning
**Note:** The `VLESS` lightweight protocol was originally developed to introduce the fallback function to cores like `xray` and `v2fly`, while reducing redundant verification/encryption. (Of course, as of now, the `trojan` protocol in `xray` also fully supports the fallback function.)
:::
::: warning
**Note:** The `VLESS` lightweight protocol was originally developed to introduce the fallback function to cores like `xray` and `v2fly`, while reducing redundant verification/encryption. (Of course, as of now, the `trojan` protocol in `xray` also fully supports the fallback function.)
:::
3. **The `[fallback dest]` is `8080`**
After `Xray` accepts traffic on port `443`, traffic belonging to the `vless` protocol is processed internally by `Xray` and forwarded to the outbound module. Traffic that is *not* `vless` protocol is forwarded to port `8080`.
After `Xray` accepts traffic on port `443`, traffic belonging to the `vless` protocol is processed internally by `Xray` and forwarded to the outbound module. Traffic that is _not_ `vless` protocol is forwarded to port `8080`.
::: warning
**Q: Is it singular or plural?**
::: warning
**Q: Is it singular or plural?**
A: Some sharp students may have noticed that in the configuration file, the keys are plural (`inbounds`, `fallbacks`), but when I explain them, I use the singular (`inbound`, `fallback`). Why?
A: Some sharp students may have noticed that in the configuration file, the keys are plural (`inbounds`, `fallbacks`), but when I explain them, I use the singular (`inbound`, `fallback`). Why?
Because the plural form in the configuration file indicates that `xray` supports N elements of the same level (i.e., N inbounds, M fallbacks, etc.). In the example analysis above, we are referring to just one of them, so I used the singular.
:::
Because the plural form in the configuration file indicates that `xray` supports N elements of the same level (i.e., N inbounds, M fallbacks, etc.). In the example analysis above, we are referring to just one of them, so I used the singular.
:::
4. **Traffic falling back to port `8080` is handled by a subsequent program**
In the example from the *Beginner's Guide*, port `8080` is handled by `Nginx`, which finds and displays the Red Panda webpage based on its configuration.
In the example from the _Beginner's Guide_, port `8080` is handled by `Nginx`, which finds and displays the Red Panda webpage based on its configuration.
5. **Summary: The complete data route for the simplest fallback in the Beginner's Guide is as follows:**
```mermaid
graph LR;
```mermaid
graph LR;
W(External HTTP:80 Request) --> N80(HTTP:80)
W(External HTTP:80 Request) --> N80(HTTP:80)
subgraph Nginx External Listener
N80 -.- N301(301 Redirect) -.- N443(HTTPS:443)
end
subgraph Nginx External Listener
N80 -.- N301(301 Redirect) -.- N443(HTTPS:443)
end
N443 --> X(Xray Listener 443) .- X1{Inbound Judgment}
X1 --> |Receive VLESS Traffic| X2(Xray Internal Rules)
X2 --> O(Xray Outbounds)
X1 ==> |Fallback Non-VLESS Traffic| N8080(Nginx:8080)
N8080:::nginxclass ==> H(index.html)
N443 --> X(Xray Listener 443) .- X1{Inbound Judgment}
X1 --> |Receive VLESS Traffic| X2(Xray Internal Rules)
X2 --> O(Xray Outbounds)
X1 ==> |Fallback Non-VLESS Traffic| N8080(Nginx:8080)
N8080:::nginxclass ==> H(index.html)
H:::nginxclass
classDef nginxclass fill:#FFFFDE
H:::nginxclass
classDef nginxclass fill:#FFFFDE
```
```
## 2. Re-understanding Fallbacks (WHAT, HOW `v1`)
@@ -191,169 +191,169 @@ How do we explain this configuration in plain language?
1. **Xray's `[inbound port]` is `443`**
This means `Xray` is responsible for listening to `HTTPS` traffic on port `443` and uses the `TLS` certificate set under `certificates` for verification.
This means `Xray` is responsible for listening to `HTTPS` traffic on port `443` and uses the `TLS` certificate set under `certificates` for verification.
2. **Xray's `[inbound protocol]` is `vless`**
`vless` protocol traffic flows directly into `Xray` for subsequent processing.
`vless` protocol traffic flows directly into `Xray` for subsequent processing.
3. **Non-`VLESS` protocol traffic has 4 different fallback targets:**
1. Traffic with `path` as `/websocket` falls back to port `1234` for processing.
2. Traffic with `path` as `/vmesstcp` falls back to port `2345` for processing.
3. Traffic with `path` as `/vmessws` falls back to port `3456` for processing.
4. All other traffic falls back to port `1310` for processing.
1. Traffic with `path` as `/websocket` falls back to port `1234` for processing.
2. Traffic with `path` as `/vmesstcp` falls back to port `2345` for processing.
3. Traffic with `path` as `/vmessws` falls back to port `3456` for processing.
4. All other traffic falls back to port `1310` for processing.
4. **`xver` set to `1` means enabling the `proxy protocol` function to pass the real source IP backwards.**
5. **The fallback structure described above is shown in the diagram below:**
```mermaid
graph LR;
```mermaid
graph LR;
W443(External HTTP:443 Request) --> X443(Xray-inbound: 443) .- X1{Inbound Judgment}
X1 --> |Protocol = VLESS Traffic| X2(Xray Internal Rules)
X2 --> O(Xray Outbounds)
W443(External HTTP:443 Request) --> X443(Xray-inbound: 443) .- X1{Inbound Judgment}
X1 --> |Protocol = VLESS Traffic| X2(Xray Internal Rules)
X2 --> O(Xray Outbounds)
X1 --> |path = /websocket Traffic| X1234(Xray-inbound:1234)
X1 --> |path = /vmesstcp Traffic| X2345(Xray-inbound:2345)
X1 --> |path = /vmessws Traffic| X3456(Xray-inbound:3456)
X1 --> |All Other Traffic| X1310(Xray-inbound:1310)
X1 --> |path = /websocket Traffic| X1234(Xray-inbound:1234)
X1 --> |path = /vmesstcp Traffic| X2345(Xray-inbound:2345)
X1 --> |path = /vmessws Traffic| X3456(Xray-inbound:3456)
X1 --> |All Other Traffic| X1310(Xray-inbound:1310)
```
```
6. **The Web Page Fallback is missing!**
That's right, clever students must have noticed that the `nginx fallback` for defending against [Active Probing] is gone!!! Why is that? Is it insecure? Don't worry, let's continue analyzing:
That's right, clever students must have noticed that the `nginx fallback` for defending against [Active Probing] is gone!!! Why is that? Is it insecure? Don't worry, let's continue analyzing:
### 5.2 The configuration segments for subsequent listening processing are as follows
1. Traffic falling back to port `1310` is verified and processed according to the configuration below:
```json
{
"port": 1310,
"listen": "127.0.0.1",
"protocol": "trojan",
"settings": {
"clients": [
{
"password": "", // Fill in your password
"level": 0,
"email": "love@example.com"
}
],
"fallbacks": [
{
"dest": 80 // Or fallback to another probe-resistant proxy
}
]
},
"streamSettings": {
"network": "tcp",
"security": "none",
"tcpSettings": {
"acceptProxyProtocol": true
}
}
}
```
```json
{
"port": 1310,
"listen": "127.0.0.1",
"protocol": "trojan",
"settings": {
"clients": [
{
"password": "", // Fill in your password
"level": 0,
"email": "love@example.com"
}
],
"fallbacks": [
{
"dest": 80 // Or fallback to another probe-resistant proxy
}
]
},
"streamSettings": {
"network": "tcp",
"security": "none",
"tcpSettings": {
"acceptProxyProtocol": true
}
}
}
```
Look, something magical happened. A new `fallbacks` section appeared here in the `trojan` protocol. As mentioned before, the `trojan` protocol in `xray` also has full fallback capabilities. So, at this point, the `trojan` protocol can perform judgment and fallback again (this is the legendary "Nested/Matryoshka" fallback):
- All `trojan` protocol traffic flows into `Xray` for subsequent processing.
- All non-`trojan` protocol traffic is forwarded to port `80`. The defense against [Active Probing] is complete!
Look, something magical happened. A new `fallbacks` section appeared here in the `trojan` protocol. As mentioned before, the `trojan` protocol in `xray` also has full fallback capabilities. So, at this point, the `trojan` protocol can perform judgment and fallback again (this is the legendary "Nested/Matryoshka" fallback):
- All `trojan` protocol traffic flows into `Xray` for subsequent processing.
- All non-`trojan` protocol traffic is forwarded to port `80`. The defense against [Active Probing] is complete!
2. Traffic falling back to port `1234`. Look closely! It is actually `vless+ws`:
```json
{
"port": 1234,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "", // Fill in your UUID
"level": 0,
"email": "love@example.com"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"acceptProxyProtocol": true, // Reminder: Delete this line if using Nginx/Caddy to reverse proxy WS
"path": "/websocket" // Must be changed to custom PATH, matching the shunting path
}
}
}
```
```json
{
"port": 1234,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "", // Fill in your UUID
"level": 0,
"email": "love@example.com"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"acceptProxyProtocol": true, // Reminder: Delete this line if using Nginx/Caddy to reverse proxy WS
"path": "/websocket" // Must be changed to custom PATH, matching the shunting path
}
}
}
```
3. Traffic falling back to port `2345`. Look closely! It is actually `vmess direct connection`:
```json
{
"port": 2345,
"listen": "127.0.0.1",
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "", // Fill in your UUID
"level": 0,
"email": "love@example.com"
}
]
},
"streamSettings": {
"network": "tcp",
"security": "none",
"tcpSettings": {
"acceptProxyProtocol": true,
"header": {
"type": "http",
"request": {
"path": [
"/vmesstcp" // Must be changed to custom PATH, matching the shunting path
]
}
}
}
}
}
```
```json
{
"port": 2345,
"listen": "127.0.0.1",
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "", // Fill in your UUID
"level": 0,
"email": "love@example.com"
}
]
},
"streamSettings": {
"network": "tcp",
"security": "none",
"tcpSettings": {
"acceptProxyProtocol": true,
"header": {
"type": "http",
"request": {
"path": [
"/vmesstcp" // Must be changed to custom PATH, matching the shunting path
]
}
}
}
}
}
```
4. Traffic falling back to port `3456`. Look closely again! It is actually `vmess+ws(+cdn)`.
::: warning Explanation
You read that right. This is one of the combinations previously recommended by v2fly, and it fully supports `CDN`. It is now included in the perfect fallback package!
:::
::: warning Explanation
You read that right. This is one of the combinations previously recommended by v2fly, and it fully supports `CDN`. It is now included in the perfect fallback package!
:::
```json
{
"port": 3456,
"listen": "127.0.0.1",
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "", // Fill in your UUID
"level": 0,
"email": "love@example.com"
}
]
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"acceptProxyProtocol": true, // Reminder: Delete this line if using Nginx/Caddy to reverse proxy WS
"path": "/vmessws" // Must be changed to custom PATH, matching the shunting path
}
}
}
```
```json
{
"port": 3456,
"listen": "127.0.0.1",
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "", // Fill in your UUID
"level": 0,
"email": "love@example.com"
}
]
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"acceptProxyProtocol": true, // Reminder: Delete this line if using Nginx/Caddy to reverse proxy WS
"path": "/vmessws" // Must be changed to custom PATH, matching the shunting path
}
}
}
```
5. **With this, we can draw the complete fallback route for the template:**
@@ -146,11 +146,11 @@ Observing the routing configuration carefully, we can see several new terms:
We will put aside `domainStrategy` for now and briefly explain the latter ones:
| Config Name | Config Value | Config Explanation |
| :---------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `“rules”` | | Its inner layer contains the detailed settings of [Routing Rules]. |
| `"inboundTag"` | `["inbound-10808"]` | The **[Basis]** for filtering traffic is the [Inbound Tag]. The specific **[Condition]** right now is only one: [Inbound source is `inbound-10808`]. |
| `"outboundTag"` | `"proxy-out-vless"` | When the above filtering condition is met (i.e., when inbound `[tag]="inbound-10808"`), `Xray` will import the traffic into the outbound with `[tag]="proxy-out-vless"`. |
| Config Name | Config Value | Config Explanation |
| :-------------: | :-----------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `“rules”` | | Its inner layer contains the detailed settings of [Routing Rules]. |
| `"inboundTag"` | `["inbound-10808"]` | The **[Basis]** for filtering traffic is the [Inbound Tag]. The specific **[Condition]** right now is only one: [Inbound source is `inbound-10808`]. |
| `"outboundTag"` | `"proxy-out-vless"` | When the above filtering condition is met (i.e., when inbound `[tag]="inbound-10808"`), `Xray` will import the traffic into the outbound with `[tag]="proxy-out-vless"`. |
In this example, we have only one inbound, and its `"inboundTag" = "inbound-10808"`. We also have only one outbound, with `[tag]="proxy-out-vless"`. Therefore, according to this routing rule, traffic flowing into `Xray` from the sole inbound port `10808` matches the filtering condition `100%`, is selected by the routing module, and is then forwarded to the sole outbound.
@@ -36,7 +36,7 @@ Let's review: what happens when the situations above cannot be matched? That's r
- When your first outbound is `[direct-out]`: **Everything needing direct connection is correct, but everything needing proxy is wrong.**
- When your first outbound is `[proxy-out-vless]`: **Everything needing proxy is correct, but everything needing direct connection is wrong.**
:::
:::
Therefore, we need a way to have our cake and eat it too. Does such a way exist? **Of course!** All we need are more **[Shunting Judgment Criteria]** beyond just **[Domain]**.
@@ -171,7 +171,7 @@ iptables -t mangle -A PREROUTING -j XRAY
Then you will find that although the SSH connection is disconnected, the transparent proxy is now available. As long as we change the system DNS to a public DNS, we can surf the Internet normally (because the gateway itself cannot be accessed now, setting the DNS to the gateway won't work).
At this point, Stage 1 is complete. The reason the gateway cannot be accessed is that the proxy rules cover *all* traffic, including traffic accessing the gateway. Imagine trying to access your local gateway on a VPS; it certainly won't work. So, we need to make this part of the traffic direct. Please see Stage 2.
At this point, Stage 1 is complete. The reason the gateway cannot be accessed is that the proxy rules cover _all_ traffic, including traffic accessing the gateway. Imagine trying to access your local gateway on a VPS; it certainly won't work. So, we need to make this part of the traffic direct. Please see Stage 2.
### Stage 2
+8 -2
View File
@@ -104,7 +104,10 @@ bash -c "$(curl -L wgcf-cli.vercel.app)"
"protocol": "wireguard",
"settings": {
"secretKey": "6CRVRLgFwGajnikoVOPTDNZnDhx3EydhPsMgpxHfBCY=",
"address": ["172.16.0.2/32", "2606:4700:110:857a:6a95:fe27:1870:2a9d/128"],
"address": [
"172.16.0.2/32",
"2606:4700:110:857a:6a95:fe27:1870:2a9d/128"
],
"peers": [
{
"publicKey": "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=",
@@ -128,7 +131,10 @@ Add a new WireGuard outbound to your existing outbounds:
"protocol": "wireguard",
"settings": {
"secretKey": "My_Private_Key",
"address": ["172.16.0.2/32", "2606:4700:110:8949:fed8:2642:a640:c8e1/128"],
"address": [
"172.16.0.2/32",
"2606:4700:110:8949:fed8:2642:a640:c8e1/128"
],
"peers": [
{
"publicKey": "Warp_Public_Key",
+11 -6
View File
@@ -105,24 +105,29 @@
<!-- The information between the BODY and /BODY tags is displayed.-->
<body>
<h1>Enter the main heading, usually the same as the title.</h1>
<p>Be <b>bold</b> in stating your key points. Put them in a list:</p>
<p>
Be <b>bold</b> in stating your key points. Put them in a list:
</p>
<ul>
<li>The first item in your list</li>
<li>The second item; <i>italicize</i> key words</li>
</ul>
<p>Improve your image by including an image.</p>
<p>
<img src="https://i.imgur.com/SEBww.jpg" alt="A Great HTML Resource" />
<img
src="https://i.imgur.com/SEBww.jpg"
alt="A Great HTML Resource"
/>
</p>
<p>
Add a link to your favorite
<a href="https://www.dummies.com/">Web site</a>. Break up your page
with a horizontal rule or two.
<a href="https://www.dummies.com/">Web site</a>. Break up your
page with a horizontal rule or two.
</p>
<hr />
<p>
Finally, link to <a href="page2.html">another page</a> in your own Web
site.
Finally, link to <a href="page2.html">another page</a> in your own
Web site.
</p>
<!-- And add a copyright notice.-->
<p>&#169; Wiley Publishing, 2011</p>
+8 -2
View File
@@ -110,7 +110,10 @@ bash -c "$(curl -L wgcf-cli.vercel.app)"
"protocol": "wireguard",
"settings": {
"secretKey": "6CRVRLgFwGajnikoVOPTDNZnDhx3EydhPsMgpxHfBCY=",
"address": ["172.16.0.2/32", "2606:4700:110:857a:6a95:fe27:1870:2a9d/128"],
"address": [
"172.16.0.2/32",
"2606:4700:110:857a:6a95:fe27:1870:2a9d/128"
],
"peers": [
{
"publicKey": "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=",
@@ -134,7 +137,10 @@ bash -c "$(curl -L wgcf-cli.vercel.app)"
"protocol": "wireguard",
"settings": {
"secretKey": "Секретный ключ",
"address": ["172.16.0.2/32", "2606:4700:110:8949:fed8:2642:a640:c8e1/128"],
"address": [
"172.16.0.2/32",
"2606:4700:110:8949:fed8:2642:a640:c8e1/128"
],
"peers": [
{
"publicKey": "Публичный ключ Warp",
+78 -71
View File
@@ -1,94 +1,101 @@
import { execSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
import { execSync } from "node:child_process"
import fs from "node:fs"
import path from "node:path"
import crypto from "node:crypto"
const ROOT = process.cwd();
const DOCS_DIR = path.resolve(ROOT, "docs");
const OUT_DIR = path.resolve(ROOT, ".vitepress/.generated");
const OUT_FILE = path.join(OUT_DIR, "contributors.json");
const ROOT = process.cwd()
const DOCS_DIR = path.resolve(ROOT, "docs")
const OUT_DIR = path.resolve(ROOT, ".vitepress/.generated")
const OUT_FILE = path.join(OUT_DIR, "contributors.json")
function walk(dir) {
const out = [];
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name);
const st = fs.statSync(p);
if (st.isDirectory()) out.push(...walk(p));
else if (p.endsWith(".md")) out.push(p);
}
return out;
const out = []
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name)
const st = fs.statSync(p)
if (st.isDirectory()) out.push(...walk(p))
else if (p.endsWith(".md")) out.push(p)
}
return out
}
function md5(s) {
return crypto.createHash("md5").update(s.trim().toLowerCase()).digest("hex");
return crypto
.createHash("md5")
.update(s.trim().toLowerCase())
.digest("hex")
}
function parseGithubUsernameFromNoreply(email = "") {
// 1) 12345+username@users.noreply.github.com
// 2) username@users.noreply.github.com
const m1 = email.match(/^[^+]+\+([^@]+)@users\.noreply\.github\.com$/i);
if (m1?.[1]) return m1[1];
const m2 = email.match(/^([^@]+)@users\.noreply\.github\.com$/i);
if (m2?.[1]) return m2[1];
return null;
// 1) 12345+username@users.noreply.github.com
// 2) username@users.noreply.github.com
const m1 = email.match(/^[^+]+\+([^@]+)@users\.noreply\.github\.com$/i)
if (m1?.[1]) return m1[1]
const m2 = email.match(/^([^@]+)@users\.noreply\.github\.com$/i)
if (m2?.[1]) return m2[1]
return null
}
function avatarUrlFor(email = "") {
const gh = parseGithubUsernameFromNoreply(email);
if (gh) {
return `https://unavatar.io/github/${encodeURIComponent(gh)}`;
}
if (email) {
return `https://www.gravatar.com/avatar/${md5(email)}?d=identicon&s=64`;
}
return `https://www.gravatar.com/avatar/?d=identicon&s=64`;
const gh = parseGithubUsernameFromNoreply(email)
if (gh) {
return `https://unavatar.io/github/${encodeURIComponent(gh)}`
}
if (email) {
return `https://www.gravatar.com/avatar/${md5(email)}?d=identicon&s=64`
}
return `https://www.gravatar.com/avatar/?d=identicon&s=64`
}
function gitContributors(fileAbsPath) {
const rel = path.relative(process.cwd(), fileAbsPath).replaceAll("\\", "/");
let raw = "";
try {
raw = execSync(`git log --follow --format="%aN|%aE" -- "${rel}"`, {
encoding: "utf8",
});
} catch {
return [];
}
const rel = path
.relative(process.cwd(), fileAbsPath)
.replaceAll("\\", "/")
let raw = ""
try {
raw = execSync(`git log --follow --format="%aN|%aE" -- "${rel}"`, {
encoding: "utf8"
})
} catch {
return []
}
const map = new Map();
raw
.split("\n")
.map((s) => s.trim())
.filter(Boolean)
.forEach((line) => {
const [name, email] = line.split("|");
const key = (email || name || "").toLowerCase();
if (!map.has(key)) {
const github = parseGithubUsernameFromNoreply(email);
map.set(key, {
name,
email,
github,
avatarUrl: avatarUrlFor(email),
commits: 0,
});
}
map.get(key).commits += 1;
});
const map = new Map()
raw
.split("\n")
.map((s) => s.trim())
.filter(Boolean)
.forEach((line) => {
const [name, email] = line.split("|")
const key = (email || name || "").toLowerCase()
if (!map.has(key)) {
const github = parseGithubUsernameFromNoreply(email)
map.set(key, {
name,
email,
github,
avatarUrl: avatarUrlFor(email),
commits: 0
})
}
map.get(key).commits += 1
})
return [...map.values()].sort((a, b) => b.commits - a.commits);
return [...map.values()].sort((a, b) => b.commits - a.commits)
}
const files = walk(DOCS_DIR);
const data = {};
const files = walk(DOCS_DIR)
const data = {}
for (const abs of files) {
const relToDocs = path.relative(DOCS_DIR, abs).replaceAll("\\", "/");
let route = "/" + relToDocs.replace(/\.md$/, "");
route = route.replace(/\/index$/, "/"); // docs/a/index.md -> /a/
data[route] = gitContributors(abs);
const relToDocs = path.relative(DOCS_DIR, abs).replaceAll("\\", "/")
let route = "/" + relToDocs.replace(/\.md$/, "")
route = route.replace(/\/index$/, "/") // docs/a/index.md -> /a/
data[route] = gitContributors(abs)
}
fs.mkdirSync(OUT_DIR, { recursive: true });
fs.writeFileSync(OUT_FILE, JSON.stringify(data, null, 2), "utf8");
console.log(`Generated contributors for ${files.length} pages -> ${OUT_FILE}`);
fs.mkdirSync(OUT_DIR, { recursive: true })
fs.writeFileSync(OUT_FILE, JSON.stringify(data, null, 2), "utf8")
console.log(
`Generated contributors for ${files.length} pages -> ${OUT_FILE}`
)
+79 -79
View File
@@ -1,114 +1,114 @@
import fs from "node:fs";
import path from "node:path";
import { execSync } from "node:child_process";
import fs from "node:fs"
import path from "node:path"
import { execSync } from "node:child_process"
const ROOT = process.cwd();
const DOCS_DIR = path.resolve(ROOT, "docs");
const OUT_DIR = path.resolve(ROOT, ".vitepress/.generated");
const OUT_FILE = path.join(OUT_DIR, "i18n-status.json");
const ROOT = process.cwd()
const DOCS_DIR = path.resolve(ROOT, "docs")
const OUT_DIR = path.resolve(ROOT, ".vitepress/.generated")
const OUT_FILE = path.join(OUT_DIR, "i18n-status.json")
const LOCALES = ["en", "ru"];
const LOCALES = ["en", "ru"]
function walk(dir) {
const out = [];
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name);
const st = fs.statSync(p);
if (st.isDirectory()) out.push(...walk(p));
else if (p.endsWith(".md")) out.push(p);
}
return out;
const out = []
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name)
const st = fs.statSync(p)
if (st.isDirectory()) out.push(...walk(p))
else if (p.endsWith(".md")) out.push(p)
}
return out
}
function gitLastCommitISO(fileAbsPath) {
const rel = path.relative(ROOT, fileAbsPath).replaceAll("\\", "/");
try {
const iso = execSync(`git log -1 --format=%cI -- "${rel}"`, {
encoding: "utf8",
}).trim();
return iso || null;
} catch {
return null;
}
const rel = path.relative(ROOT, fileAbsPath).replaceAll("\\", "/")
try {
const iso = execSync(`git log -1 --format=%cI -- "${rel}"`, {
encoding: "utf8"
}).trim()
return iso || null
} catch {
return null
}
}
function toRouteFromDocsRel(relToDocs) {
let route = "/" + relToDocs.replace(/\.md$/, "");
route = route.replace(/\/index$/, "/");
return route;
let route = "/" + relToDocs.replace(/\.md$/, "")
route = route.replace(/\/index$/, "/")
return route
}
function ensureEmptyPlaceholder(locale, relNoLocale) {
const tAbs = path.join(DOCS_DIR, locale, relNoLocale); // docs/en/xxx.md
if (fs.existsSync(tAbs)) return;
const tAbs = path.join(DOCS_DIR, locale, relNoLocale) // docs/en/xxx.md
if (fs.existsSync(tAbs)) return
fs.mkdirSync(path.dirname(tAbs), { recursive: true });
fs.writeFileSync(tAbs, "", "utf8");
fs.mkdirSync(path.dirname(tAbs), { recursive: true })
fs.writeFileSync(tAbs, "", "utf8")
}
const zhFiles = walk(DOCS_DIR).filter((p) => {
const rel = path.relative(DOCS_DIR, p).replaceAll("\\", "/");
return !LOCALES.some((l) => rel.startsWith(l + "/"));
});
const rel = path.relative(DOCS_DIR, p).replaceAll("\\", "/")
return !LOCALES.some((l) => rel.startsWith(l + "/"))
})
const zhByRel = new Map(); // relToDocs -> abs
const zhByRel = new Map() // relToDocs -> abs
for (const abs of zhFiles) {
const relToDocs = path.relative(DOCS_DIR, abs).replaceAll("\\", "/");
zhByRel.set(relToDocs, abs);
const relToDocs = path.relative(DOCS_DIR, abs).replaceAll("\\", "/")
zhByRel.set(relToDocs, abs)
}
const data = {};
const data = {}
for (const locale of LOCALES) {
const localeDir = path.join(DOCS_DIR, locale);
if (!fs.existsSync(localeDir)) continue;
const localeDir = path.join(DOCS_DIR, locale)
if (!fs.existsSync(localeDir)) continue
const tFiles = walk(localeDir);
for (const tAbs of tFiles) {
const relToDocs = path.relative(DOCS_DIR, tAbs).replaceAll("\\", "/"); // en/config/log.md
const relNoLocale = relToDocs.replace(new RegExp(`^${locale}/`), ""); // config/log.md
const zhAbs = zhByRel.get(relNoLocale);
const tFiles = walk(localeDir)
for (const tAbs of tFiles) {
const relToDocs = path.relative(DOCS_DIR, tAbs).replaceAll("\\", "/") // en/config/log.md
const relNoLocale = relToDocs.replace(new RegExp(`^${locale}/`), "") // config/log.md
const zhAbs = zhByRel.get(relNoLocale)
const tRoute = toRouteFromDocsRel(relToDocs); // /en/config/log
const zhRoute = toRouteFromDocsRel(relNoLocale); // /config/log
const tRoute = toRouteFromDocsRel(relToDocs) // /en/config/log
const zhRoute = toRouteFromDocsRel(relNoLocale) // /config/log
const tISO = gitLastCommitISO(tAbs);
const zhISO = zhAbs ? gitLastCommitISO(zhAbs) : null;
const tISO = gitLastCommitISO(tAbs)
const zhISO = zhAbs ? gitLastCommitISO(zhAbs) : null
const stale =
Boolean(zhISO && tISO) &&
new Date(tISO).getTime() < new Date(zhISO).getTime();
const stale =
Boolean(zhISO && tISO) &&
new Date(tISO).getTime() < new Date(zhISO).getTime()
data[tRoute] = {
locale,
zhRoute,
translated: true,
stale,
tLastUpdated: tISO,
zhLastUpdated: zhISO,
};
data[tRoute] = {
locale,
zhRoute,
translated: true,
stale,
tLastUpdated: tISO,
zhLastUpdated: zhISO
}
}
}
for (const [zhRel, zhAbs] of zhByRel.entries()) {
const zhRoute = toRouteFromDocsRel(zhRel);
const zhISO = gitLastCommitISO(zhAbs);
const zhRoute = toRouteFromDocsRel(zhRel)
const zhISO = gitLastCommitISO(zhAbs)
for (const locale of LOCALES) {
const tRoute = "/" + locale + (zhRoute === "/" ? "/" : zhRoute);
if (!data[tRoute]) {
data[tRoute] = {
locale,
zhRoute,
translated: false,
stale: true,
tLastUpdated: null,
zhLastUpdated: zhISO,
};
ensureEmptyPlaceholder(locale, zhRel);
}
for (const locale of LOCALES) {
const tRoute = "/" + locale + (zhRoute === "/" ? "/" : zhRoute)
if (!data[tRoute]) {
data[tRoute] = {
locale,
zhRoute,
translated: false,
stale: true,
tLastUpdated: null,
zhLastUpdated: zhISO
}
ensureEmptyPlaceholder(locale, zhRel)
}
}
}
fs.mkdirSync(OUT_DIR, { recursive: true });
fs.writeFileSync(OUT_FILE, JSON.stringify(data, null, 2), "utf8");
console.log(`Generated i18n status -> ${OUT_FILE}`);
fs.mkdirSync(OUT_DIR, { recursive: true })
fs.writeFileSync(OUT_FILE, JSON.stringify(data, null, 2), "utf8")
console.log(`Generated i18n status -> ${OUT_FILE}`)