From 9c0b0e37dc08c6c3dd9e7191cb1f7ac3ac2cf2c8 Mon Sep 17 00:00:00 2001 From: Meow <197331664+Meo597@users.noreply.github.com> Date: Sat, 9 May 2026 06:47:38 +0800 Subject: [PATCH] EN Refactor Transports --- .vitepress/menus/nav.en.mts | 2 +- .vitepress/menus/sidebar.en.mts | 41 +- docs/en/about/news.md | 2 +- docs/en/config/features/fallback.md | 4 +- docs/en/config/inbound.md | 6 +- docs/en/config/inbounds/tunnel.md | 2 +- docs/en/config/inbounds/vless.md | 2 +- docs/en/config/outbound.md | 16 +- docs/en/config/outbounds/freedom.md | 2 +- docs/en/config/outbounds/hysteria.md | 2 +- docs/en/config/outbounds/vless.md | 2 +- docs/en/config/transport.md | 1269 +--------------------- docs/en/config/transports/finalmask.md | 404 +++++++ docs/en/config/transports/httpupgrade.md | 4 +- docs/en/config/transports/index.md | 16 +- docs/en/config/transports/mkcp.md | 2 +- docs/en/config/transports/reality.md | 203 ++++ docs/en/config/transports/sockopt.md | 298 +++++ docs/en/config/transports/tls.md | 338 ++++++ 19 files changed, 1362 insertions(+), 1253 deletions(-) create mode 100644 docs/en/config/transports/finalmask.md create mode 100644 docs/en/config/transports/reality.md create mode 100644 docs/en/config/transports/sockopt.md create mode 100644 docs/en/config/transports/tls.md diff --git a/.vitepress/menus/nav.en.mts b/.vitepress/menus/nav.en.mts index b178466f..19e27f84 100644 --- a/.vitepress/menus/nav.en.mts +++ b/.vitepress/menus/nav.en.mts @@ -9,7 +9,7 @@ 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: "Transport Configuration", link: "/en/config/transports/" } ] }, { diff --git a/.vitepress/menus/sidebar.en.mts b/.vitepress/menus/sidebar.en.mts index e6a79e6f..5f129975 100644 --- a/.vitepress/menus/sidebar.en.mts +++ b/.vitepress/menus/sidebar.en.mts @@ -38,7 +38,7 @@ export const sidebar: DefaultTheme.Config["sidebar"] = { { text: "Routing", link: "/en/config/routing.md" }, { text: "Statistics", link: "/en/config/stats.md" }, { - text: "Transport (uTLS, REALITY)", + text: "Transport Configuration", link: "/en/config/transport.md" }, { text: "Metrics", link: "/en/config/metrics.md" }, @@ -101,23 +101,42 @@ export const sidebar: DefaultTheme.Config["sidebar"] = { ] }, { - text: "Transports", + text: "Transport Configuration", link: "/en/config/transports/", collapsed: true, items: [ - { text: "RAW", link: "/en/config/transports/raw.md" }, { - text: "XHTTP: Beyond REALITY", - link: "/en/config/transports/xhttp.md" + text: "Transport Methods", + items: [ + { text: "RAW", link: "/en/config/transports/raw.md" }, + { + text: "XHTTP: Beyond REALITY", + 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: "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: "Transport Security", + items: [ + { text: "REALITY", link: "/en/config/transports/reality.md" }, + { text: "TLS", link: "/en/config/transports/tls.md" } + ] }, - { text: "Hysteria", link: "/en/config/transports/hysteria.md" } + { + text: "Additional Configuration", + items: [ + { text: "FinalMask", link: "/en/config/transports/finalmask.md" }, + { text: "Sockopt", link: "/en/config/transports/sockopt.md" } + ] + } ] } ], diff --git a/docs/en/about/news.md b/docs/en/about/news.md index 16bab981..261abb23 100644 --- a/docs/en/about/news.md +++ b/docs/en/about/news.md @@ -350,7 +350,7 @@ The weather is getting cooler, but the pace of development has not cooled down. ## 2022.8.28 [v1.5.10](https://github.com/XTLS/Xray-core/releases/tag/v1.5.10) -The underlying transport now supports more reasonable TCP Keepalive configurations. +`sockopt` now supports more reasonable TCP Keepalive configurations. ## 2022.6.20 [v1.5.8](https://github.com/XTLS/Xray-core/releases/tag/v1.5.8) diff --git a/docs/en/config/features/fallback.md b/docs/en/config/features/fallback.md index 4001b7fb..e9f1de92 100644 --- a/docs/en/config/features/fallback.md +++ b/docs/en/config/features/fallback.md @@ -38,7 +38,7 @@ An array containing a series of powerful fallback distribution configurations. The `fallbacks` item is optional and can only be used with the TCP+TLS transport combination. -- When this item has child elements, [Inbound TLS](../transport.md#tlsobject) must set `"alpn":["http/1.1"]`. +- When this item has child elements, [Inbound TLS](../transports/tls.md#tlsobject) must set `"alpn":["http/1.1"]`. Usually, you need to first set a default fallback with both `alpn` and `path` omitted or empty, and then configure other traffic splitting as needed. @@ -56,7 +56,7 @@ Attempts to match the TLS ALPN negotiation result. Empty means any. Default is ` Xray will only attempt to read the TLS ALPN negotiation result when necessary. If successful, it outputs `realAlpn =` to the info log. Usage: Solves the issue where Nginx's h2c service cannot be compatible with http/1.1 simultaneously. Nginx would require two `listen` lines, for 1.1 and h2c respectively. -Note: When `fallbacks` `alpn` contains `"h2"`, [Inbound TLS](../transport.md#tlsobject) needs to set `"alpn":["h2","http/1.1"]` to support h2 access. +Note: When `fallbacks` `alpn` contains `"h2"`, [Inbound TLS](../transports/tls.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. diff --git a/docs/en/config/inbound.md b/docs/en/config/inbound.md index e8b898fc..799f6f70 100644 --- a/docs/en/config/inbound.md +++ b/docs/en/config/inbound.md @@ -38,7 +38,7 @@ The solution is not to listen on `0.0.0.0` but to listen on the specific IP addr Supports Unix domain sockets in absolute path format, such as `"/dev/shm/domain.socket"`. You can add `@` at the beginning to represent [abstract](https://www.man7.org/linux/man-pages/man7/unix.7.html), and `@@` for abstract with padding. -When filling in a Unix domain socket, `port` and `allocate` will be ignored. The protocol can currently be VLESS, VMess, or Trojan, and applies only to TCP-based underlying transports, such as `tcp`, `websocket`, `grpc`. UDP-based transports like `mkcp` are not supported. +When filling in a Unix domain socket, `port` and `allocate` will be ignored. The protocol can currently be VLESS, VMess, or Trojan, and applies only to TCP-based transport methods, such as `tcp`, `websocket`, `grpc`. UDP-based transports like `mkcp` are not supported. When filling in a Unix domain socket, you can use the format `"/dev/shm/domain.socket,0666"`, i.e., adding a comma and access permission indicators after the socket, to specify the access permissions of the socket. This can be used to solve socket permission issues that occur by default. @@ -62,9 +62,9 @@ Connection protocol name. See the list of available [Inbound Protocols](./inboun Specific configuration content, which varies by protocol. See `InboundConfigurationObject` in each protocol section for details. -> `streamSettings`: [StreamSettingsObject](./transport.md#streamsettingsobject) +> `streamSettings`: [StreamSettingsObject](./transport.md) -Underlying transport method (transport) is the way the current Xray node connects with other nodes. +Transport configuration for this inbound. > `tag`: string > The identifier of this inbound connection, used to locate this connection in other configurations. diff --git a/docs/en/config/inbounds/tunnel.md b/docs/en/config/inbounds/tunnel.md index 280cdc61..64eb61e0 100644 --- a/docs/en/config/inbounds/tunnel.md +++ b/docs/en/config/inbounds/tunnel.md @@ -50,7 +50,7 @@ A map mapping local ports to required remote addresses/ports (if the inbound lis When set to `true`, dokodemo-door will recognize data forwarded by iptables and forward it to the corresponding target address. -Please refer to the `tproxy` setting in [Transport Configuration](../transport.md#sockoptobject). +Please refer to the `tproxy` setting in [Sockopt](../transports/sockopt.md#sockoptobject). > `userLevel`: number diff --git a/docs/en/config/inbounds/vless.md b/docs/en/config/inbounds/vless.md index cdf1f205..60352a03 100644 --- a/docs/en/config/inbounds/vless.md +++ b/docs/en/config/inbounds/vless.md @@ -118,7 +118,7 @@ Currently, the following flow control modes are available in the inbound protoco XTLS is only available under the following combinations: -- TCP+TLS/Reality: In this case, encrypted data is directly copied at the underlying layer (if transmitting TLS 1.3). +- TCP+TLS/REALITY: In this case, encrypted data is directly copied at the underlying layer (if transmitting TLS 1.3). - VLESS Encryption: No underlying transport restrictions. If the underlying layer does not support direct copying (see above), it only penetrates Encryption. > `reverse`: struct diff --git a/docs/en/config/outbound.md b/docs/en/config/outbound.md index 710d8af7..c112edbe 100644 --- a/docs/en/config/outbound.md +++ b/docs/en/config/outbound.md @@ -63,9 +63,9 @@ The identifier for this outbound connection, used to locate this connection in o When not empty, its value must be **unique** among all `tag`s. ::: -> `streamSettings`: [StreamSettingsObject](./transport.md#streamsettingsobject) +> `streamSettings`: [StreamSettingsObject](./transport.md) -The underlying transport method is the way the current Xray node connects with other nodes. +Transport configuration for this outbound. > `proxySettings`: [ProxySettingsObject](#proxysettingsobject) @@ -79,10 +79,10 @@ Specific configuration related to Mux. If this outbound attempts to send a domain request, this controls whether it is resolved/how it is resolved to an IP before sending. -The default value is `AsIs`, meaning it is sent to the remote server as is. All parameter meanings are roughly equivalent to `domainStrategy` in [sockopt](./transport.md#sockoptobject). +The default value is `AsIs`, meaning it is sent to the remote server as is. All parameter meanings are roughly equivalent to `domainStrategy` in [Sockopt](./transports/sockopt.md#sockoptobject). ::: tip -This controls **proxied requests**. If the address of the outbound proxy server is a domain name, and you need to select a resolution strategy for the domain name itself, you should configure `domainStrategy` in [sockopt](./transport.md#sockoptobject). +This controls **proxied requests**. If the address of the outbound proxy server is a domain name, and you need to select a resolution strategy for the domain name itself, you should configure `domainStrategy` in [Sockopt](./transports/sockopt.md#sockoptobject). ::: ### ProxySettingsObject @@ -99,15 +99,15 @@ This controls **proxied requests**. If the address of the outbound proxy server When the identifier of another outbound is specified, data sent by this outbound will be forwarded to the specified outbound for transmission. ::: danger -This option conflicts with [SockOpt.dialerProxy](./transport.md#sockoptobject). Choose one as needed. +This option conflicts with [Sockopt.dialerProxy](./transports/sockopt.md#sockoptobject). Choose one as needed. -By default, this forwarding method **does not go through** the underlying transport method (REALITY/XHTTP/gRPC...), meaning the `streamSettings` of this outbound will not take effect.
-If you need forwarding that supports underlying transport methods, please use `SockOpt.dialerProxy` instead or set `transportLayer` to `true`. +By default, this forwarding method **ignores** this outbound's own transport configuration (such as XHTTP, REALITY, or Sockopt), meaning the `streamSettings` of this outbound will not take effect.
+If you need forwarding that works together with `streamSettings`, please use `Sockopt.dialerProxy` instead or set `transportLayer` to `true` here. ::: > `transportLayer`: true | false -`true` converts this setting to `SockOpt.dialerProxy` to support forwarding via underlying transport methods. The default is `false`, meaning no conversion. +`true` converts this setting to `Sockopt.dialerProxy` so the forwarding can use this outbound's `streamSettings`. The default is `false`. ### MuxObject diff --git a/docs/en/config/outbounds/freedom.md b/docs/en/config/outbounds/freedom.md index c81b95ac..b9d7b2c9 100644 --- a/docs/en/config/outbounds/freedom.md +++ b/docs/en/config/outbounds/freedom.md @@ -57,7 +57,7 @@ This outbound has a default safety policy in server-side and reverse-proxy scena Default value `"AsIs"`. -The meanings of all parameters are roughly equivalent to `domainStrategy` in [sockopt](../transport.md#sockoptobject). +The meanings of all parameters are roughly equivalent to `domainStrategy` in [Sockopt](../transports/sockopt.md#sockoptobject). Only using `"AsIs"` here allows passing the domain name to the subsequent `sockopt` module. If set to non-`"AsIs"` here, causing the domain to be resolved to a specific IP, it will invalidate the subsequent `sockopt.domainStrategy` and its related `happyEyeballs`. (There is no negative impact if these two settings are not adjusted). diff --git a/docs/en/config/outbounds/hysteria.md b/docs/en/config/outbounds/hysteria.md index ad8d8ced..16c950b7 100644 --- a/docs/en/config/outbounds/hysteria.md +++ b/docs/en/config/outbounds/hysteria.md @@ -2,7 +2,7 @@ Client implementation of the Hysteria protocol. -This page is very simple because the Hysteria protocol is actually composed of a simple proxy control protocol and a tuned QUIC underlying transport. In Xray, the proxy protocol and the underlying transport are separated. For more details (such as `brutal`), please refer to [hysteriaSettings](../transports/hysteria.md) [finalmask.quicParams](../transport.md#quicParams) in the underlying transport section. +This page is very simple because the Hysteria protocol is actually composed of a simple proxy control protocol and a tuned QUIC transport implementation. In Xray, the proxy protocol and transport configuration are separated. For more details (such as `brutal`), please refer to transport configuration items [hysteriaSettings](../transports/hysteria.md) and [FinalMask.quicParams](../transports/finalmask.md#quicparams). ::: tip The `hysteria protocol` itself has no authentication. When using with a non `hysteria` transport layer, it will be unable to proxy `udp`, and using it with other transport layers is not recommended. diff --git a/docs/en/config/outbounds/vless.md b/docs/en/config/outbounds/vless.md index 5d87674b..73debca1 100644 --- a/docs/en/config/outbounds/vless.md +++ b/docs/en/config/outbounds/vless.md @@ -84,7 +84,7 @@ Currently, the following flow control modes are available in the outbound protoc XTLS is available only in the following combinations: -- **TCP+TLS/Reality**: In this case, if transmitting TLS 1.3, the core will attempt to Splice encrypted data at the bottom layer. If successful, it saves all core IO overhead. +- **TCP+TLS/REALITY**: In this case, if transmitting TLS 1.3, the core will attempt to Splice encrypted data at the bottom layer. If successful, it saves all core IO overhead. - **VLESS Encryption**: No underlying transport restrictions. If the underlying transport is not TCP, it only attempts to penetrate Encryption, saving Encryption overhead. If it is TCP, it will still attempt to perform Splice. ::: tip About Splice diff --git a/docs/en/config/transport.md b/docs/en/config/transport.md index b3f3ee27..15328642 100644 --- a/docs/en/config/transport.md +++ b/docs/en/config/transport.md @@ -1,12 +1,22 @@ -# Transport (uTLS, REALITY) +# Transport Configuration -Transport is the method used by the current Xray node to establish connections with other nodes. +Transport configuration controls how the current Xray instance communicates with its peer. That peer may be another Xray node, or it may simply be a public network target. -Transport specifies a stable method for data transmission. Generally, both ends of a network connection need to have symmetrical transport methods. For example, if one end uses WebSocket, the other end must also use WebSocket; otherwise, the connection cannot be established. +It covers the part below the proxy protocol itself, including transport methods, transport security, and additional low-level behavior. + +These three categories belong to different layers and can usually be combined: + +- Transport methods specify how the data stream is carried, such as RAW, WebSocket, gRPC, or Hysteria. +- Transport security specifies the protection mechanism used during transport, such as TLS or REALITY. +- Additional configuration supplements low-level network behavior and final traffic obfuscation. + +Some transport settings directly affect how a connection is established with the remote side. For settings that require negotiation, both sides usually need compatible configurations. For example, if one side uses WebSocket, the other side must also use WebSocket, otherwise the connection cannot be established. + +For direct outbounds such as [Freedom](./outbounds/freedom.md), the peer is not necessarily another Xray node and may simply be a public network target. In that case transport configuration is not used to negotiate with another Xray instance, but to control how the local connection is sent. In that scenario, only `sockopt` is available. ## StreamSettingsObject -`StreamSettingsObject` corresponds to the `streamSettings` item in [`InboundObject`](./inbound.md) or [`OutboundObject`](./outbound.md). Each inbound or outbound can be configured with different transport settings independently, and `streamSettings` can be set to perform some transport configurations. +`StreamSettingsObject` corresponds to the `streamSettings` item in [`InboundObject`](./inbound.md) or [`OutboundObject`](./outbound.md). Each inbound or outbound can be configured with its own transport settings. ```json { @@ -15,11 +25,9 @@ Transport specifies a stable method for data transmission. Generally, both ends { // ... "streamSettings": { - // [!code focus:34] + // [!code focus:16] + // Transport methods "network": "raw", - "security": "none", - "tlsSettings": {}, - "realitySettings": {}, "rawSettings": {}, "xhttpSettings": {}, "kcpSettings": {}, @@ -27,1256 +35,83 @@ Transport specifies a stable method for data transmission. Generally, both ends "wsSettings": {}, "httpupgradeSettings": {}, "hysteriaSettings": {}, - "finalmask": { - "tcp": [], - "udp": [], - "quicParams": {} - }, - "sockopt": { - "mark": 0, - "tcpMaxSeg": 1440, - "tcpFastOpen": false, - "tproxy": "off", - "domainStrategy": "AsIs", - "happyEyeballs": {}, - "dialerProxy": "", - "acceptProxyProtocol": false, - "tcpKeepAliveInterval": 0, - "tcpKeepAliveIdle": 300, - "tcpUserTimeout": 10000, - "tcpCongestion": "bbr", - "interface": "wg0", - "v6only": false, - "tcpWindowClamp": 600, - "tcpMptcp": false - } + // Transport security + "security": "none", + "realitySettings": {}, + "tlsSettings": {}, + // Additional configuration + "finalmask": {}, + "sockopt": {} } } ] } ``` -> `network`: "raw" | "xhttp" | "kcp" | "grpc" | "ws" | "httpupgrade" | "hysteria" +> `network`: "raw" | "xhttp" | "mkcp" | "grpc" | "websocket" | "httpupgrade" | "hysteria" -The type of transport method used for the connection data stream. The default value is `"raw"`. - -::: tip -After version v24.9.30, to better reflect actual behavior, the TCP transport method has been renamed to RAW. For compatibility, `"network": "raw"` and `"network": "tcp"`, as well as `rawSettings` and `tcpSettings`, are aliases for each other. -::: - -> `security`: "none" | "tls" | "reality" - -Whether to enable transport layer encryption. Supported options are: - -- `"none"`: Indicates no encryption (default value). -- `"tls"`: Indicates using [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security). -- `"reality"`: Indicates using REALITY. - -> `tlsSettings`: [TLSObject](#tlsobject) - -TLS configuration. TLS is provided by Golang. Usually, the TLS negotiation result is TLS 1.3. DTLS is not supported. - -> `realitySettings`: [RealityObject](#realityobject) - -Reality configuration. Reality is an original black technology from Xray. Reality offers higher security than TLS, and its configuration method is consistent with TLS. - -::: tip -Reality is currently the most secure transport encryption scheme, and the traffic type appears consistent with normal web browsing from the outside. Enabling Reality and configuring an appropriate XTLS Vision flow control mode can achieve several times or even more than ten times performance improvement. -::: +Transport method used by the data stream. The default value is `raw`. > `rawSettings`: [RawObject](./transports/raw.md) -RAW configuration for the current connection. Only valid when this connection uses RAW. +RAW configuration for the data stream. Only valid when `network` is `raw`. -> `xhttpSettings`: [XHTTP: Beyond REALITY](https://github.com/XTLS/Xray-core/discussions/4113) +> `xhttpSettings`: [XHTTPObject](./transports/xhttp.md) -XHTTP configuration for the current connection. Only valid when this connection uses XHTTP. +XHTTP configuration for the data stream. Only valid when `network` is `xhttp`. > `kcpSettings`: [KcpObject](./transports/mkcp.md) -mKCP configuration for the current connection. Only valid when this connection uses mKCP. +mKCP configuration for the data stream. Only valid when `network` is `mkcp`. > `grpcSettings`: [GRPCObject](./transports/grpc.md) -gRPC configuration for the current connection. Only valid when this connection uses gRPC. +gRPC configuration for the data stream. Only valid when `network` is `grpc`. > `wsSettings`: [WebSocketObject](./transports/websocket.md) -WebSocket configuration for the current connection. Only valid when this connection uses WebSocket. +WebSocket configuration for the data stream. Only valid when `network` is `websocket`. -> `httpupgradeSettings`: [HttpUpgradeObject](./transports/httpupgrade.md) +> `httpupgradeSettings`: [HTTPUpgradeObject](./transports/httpupgrade.md) -HTTPUpgrade configuration for the current connection. Only valid when this connection uses HTTPUpgrade. +HTTPUpgrade configuration for the data stream. Only valid when `network` is `httpupgrade`. > `hysteriaSettings`: [HysteriaObject](./transports/hysteria.md) -Hysteria configuration for the current connection. Only valid when this connection uses Hysteria. +Hysteria configuration for the data stream. Only valid when `network` is `hysteria`. -> `sockopt`: [SockoptObject](#sockoptobject) +--- -Specific configurations related to transparent proxying. +> `security`: "none" | "reality" | "tls" -> `finalmask`: [FinalMaskObject](#finalmaskobject) +Whether to enable transport security. Supported options are: -FinalMask configuration, used for general traffic obfuscation. +- `"none"` means disabled (default). +- `"reality"` means using REALITY. +- `"tls"` means using [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security). -### TLSObject +> `realitySettings`: [RealityObject](./transports/reality.md) -```json -{ - "serverName": "xray.com", - "verifyPeerCertByName": "", - "rejectUnknownSni": false, - "allowInsecure": false, - "alpn": ["h2", "http/1.1"], - "minVersion": "1.2", - "maxVersion": "1.3", - "cipherSuites": "Enter the cipher suite names you need here, separated by :", - "certificates": [], - "disableSystemRoot": false, - "enableSessionResumption": false, - "fingerprint": "", - "pinnedPeerCertSha256": "", - "curvePreferences": [""], - "masterKeyLog": "", - "echServerKeys": "", - "echConfigList": "", - "echSockopt": {} -} -``` +REALITY configuration. REALITY is a modified form of TLS that uses the appearance and handshake characteristics of a target site as camouflage. -> `serverName`: string - -Server name. The server certificate's SAN must contain this value. It can be a domain name or an IP address. If it is a domain name, it will be sent in the SNI extension of the Client Hello. IP addresses will not send the SNI extension (SNI extension does not allow IP addresses). If filling in IPv6, use `[]` to wrap it. - -When left empty, the value in `address` (if it is a domain name) is automatically used. - -Special value `"FromMitM"`: This causes it to use the SNI contained in the TLS decrypted from the dokodemo-door inbound. - -> `verifyPeerCertByName`: string - -Client-only. The SNI used for certificate verification. Multiple domains can be separated by `,` (only one SAN in the certificate needs to be in this list). This will override the `serverName` used for verification, intended for special purposes such as domain fronting. - -Special value `"FromMitM"`: This causes it to additionally include the SNI contained in the TLS decrypted from the dokodemo-door inbound. - -> `rejectUnknownSni`: bool - -When set to `true`, the server refuses the TLS handshake if the received SNI does not match the certificate domain. Default is `false`. - -> `alpn`: \[ string \] - -An array of strings specifying the ALPN values during TLS handshake. Default value is `["h2", "http/1.1"]`. - -Special value: `["FromMitM"]` (when this is the only element) will cause the outbound TLS to use the ALPN used by the TLS connection decrypted from the dokodemo-door inbound. - -> `minVersion`: string - -`minVersion` is the minimum acceptable TLS version. - -> `maxVersion`: string - -`maxVersion` is the maximum acceptable TLS version. - -> `cipherSuites`: string - -`CipherSuites` is used to configure the list of supported cipher suites, separated by `:`. - -You can find Golang cipher suite names and descriptions [here](https://golang.org/src/crypto/tls/cipher_suites.go#L500) or [here](https://golang.org/src/crypto/tls/cipher_suites.go#L44). - -::: danger -The above two configuration items are optional and usually do not affect security. Golang automatically selects based on the device when not configured. Do not configure this option if you are unfamiliar with it; you are responsible for issues caused by improper configuration. -::: - -> `allowInsecure`: true | false - -Whether to allow insecure connections (client-only). Default value is `false`. - -When set to `true`, Xray will not check the validity of the TLS certificate provided by the remote host. - -::: danger -~~For security reasons, this option should not be set to `true` in actual scenarios, otherwise, you may suffer from Man-in-the-Middle attacks.~~ - -This option is deprecated. Use `pinnedPeerCertSha256` to manually specify the required certificate. -::: - -> `disableSystemRoot`: true | false - -Whether to disable the operating system's built-in CA certificates. Default value is `false`. - -When set to `true`, Xray will only use certificates specified in `certificates` for TLS handshake. When set to `false`, Xray will only use the OS's built-in CA certificates for TLS handshake. - -> `enableSessionResumption`: true | false - -Whether to enable session resumption. Disabled by default. Session resumption negotiation will only be attempted when both the server and client enable it. - -If negotiation is successful, certificates do not need to be transmitted during the handshake. Saves a tiny bit of handshake time (almost negligible). - -Note: This is not TLS 0-RTT. gotls does not support this feature yet. It will not reduce the RTT of the TLS handshake. - -> `fingerprint` : string - -This parameter is used to configure the fingerprint of the specified `TLS Client Hello`. Default is `chrome`. To revert to native go TLS, set to `unsafe`. When enabled, Xray will **simulate** `TLS` fingerprints via the uTLS library or generate them randomly. Supports three configuration methods: - -1. Latest versions of common browsers, including: - - `"chrome"` - - `"firefox"` - - `"safari"` - - `"ios"` - - `"android"` - - `"edge"` - - `"360"` - - `"qq"` - -2. Automatically generate a fingerprint when Xray starts: - - `"random"`: Randomly select one from newer browser versions. - - `"randomized"`: Completely randomly generate a unique fingerprint (100% supports TLS 1.3 using X25519). - -3. Use uTLS native fingerprint variable names, e.g., `"HelloRandomizedNoALPN"`, `"HelloChrome_106_Shuffle"`. See the [uTLS library](https://github.com/refraction-networking/utls/blob/master/u_common.go#L434) for the full list. +Only valid when `security` is `reality`. ::: tip -This feature only **simulates** the `TLS Client Hello` fingerprint. Behavior and other fingerprints are the same as Golang. If you wish to simulate browser `TLS` fingerprints and behavior more completely, you can use [Browser Dialer](./transports/websocket.md#browser-dialer). +REALITY is currently one of the most secure transport-security schemes, and from the outside its traffic looks consistent with ordinary web traffic. Enabling REALITY together with a suitable XTLS Vision flow-control mode can also deliver performance gains of several times or even more than ten times. ::: -::: tip -When using this feature, some TLS options affecting TLS fingerprints will be overwritten by the uTLS library and will no longer take effect, such as ALPN. -Parameters passed include: -`"serverName"`, `"disableSystemRoot"`, `"pinnedPeerCertSha256"`, `"masterKeyLog"`. -::: +> `tlsSettings`: [TLSObject](./transports/tls.md) -> `pinnedPeerCertSha256`: string +TLS configuration. TLS is provided by Go. In normal cases the negotiation result is TLS 1.3. DTLS is not supported. -Used to specify the SHA256 hash of the remote server's certificate. It uses hex encoding and is case-insensitive. For example: `e8e2d387fdbffeb38e9c9065cf30a97ee23c0e3d32ee6f78ffae40966befccc9`. You can specify multiple hash values separated by `,`; verification passes if any of them match. +Only valid when `security` is `tls`. -This encoding matches the SHA-256 Certificate Fingerprint found in the Chrome certificate viewer and the format used on crt.sh. You can calculate it using `xray tls hash --cert ` or `openssl x509 -noout -fingerprint -sha256 -in cert.pem` (the format with colons generated by OpenSSL is supported). Additionally, `xray tls ping` will output the remote certificate's SHA256 hash. +--- -This mechanism overrides the default certificate validation and operates in two scenarios: +> `finalmask`: [FinalMaskObject](./transports/finalmask.md) -- 1. If the core finds that the matching hash belongs to a leaf certificate, verification passes immediately. -- 2. If the core finds that the matching hash belongs to a CA certificate (either a root or intermediate certificate), it will use the value in `serverName` to verify if the leaf certificate is validly signed by that CA. +FinalMask configuration, used for the final stage of traffic obfuscation. -> `certificates`: \[ [CertificateObject](#certificateobject) \] +> `sockopt`: [SockoptObject](./transports/sockopt.md) -List of certificates, where each item represents a certificate (fullchain is recommended). - -::: tip -If you want to get an A/A+ rating on ssllibs or myssl, please refer to [this discussion](https://github.com/XTLS/Xray-core/discussions/56#discussioncomment-215600). -::: - -> `curvePreferences`: \[ string \] - -An array of strings specifying the curves supported when performing ECDHE in TLS handshake. Supported curves are as follows (case-insensitive): - -``` -CurveP256 -CurveP384 -CurveP521 -X25519 -X25519MLKEM768 -SecP256r1MLKEM768* -SecP384r1MLKEM1024* -``` - -\*: Not supported by utls - -The default value as of go1.26 includes all of the above curves. Adjusting the order does not make the client or server prefer a particular curve; the actual curve will be negotiated by the key exchange mechanism itself. - -> `masterKeyLog` : string - -(Pre)-Master-Secret log file path, can be used by software like Wireshark to decrypt TLS connections sent by Xray. - -> `echServerKeys` : string - -Server-only parameter. Used to enable Encrypted Client Hello on the server. - -Use `xray tls ech --serverName example.com` to generate usable ECH Server Key and corresponding Config. `example.com` is the SNI exposed externally when SNI is encrypted; you can fill in whatever you want. The Server Key contains ECHConfig. If you accidentally lose the Config used by the client, use `xray tls ech -i "your server key"` to retrieve it. You can publish it in the HTTPS record of DNS, refer to the format [here](https://dns.google/query?name=encryptedsni.com&rr_type=HTTPS) or RFC 9460. - -Note that after configuring ECH, the server still accepts normal non-ECH connections. - -> `echConfigList` : string - -Client-only parameter. Configures ECHConfig. If not empty, it means the client enables Encrypted Client Hello. Supports two formats: - -The first is a fixed ECHConfig string, e.g., `"AF7+DQBaAAAgACA51i3Ssu4wUMV4FNCc8iRX5J+YC4Bhigz9sacl2lCfSQAkAAEAAQABAAIAAQADAAIAAQACAAIAAgADAAMAAQADAAIAAwADAAtleGFtcGxlLmNvbQAA"` - -The second is querying from a DNS server. For example, when using a CDN, you can dynamically obtain the configured ECHConfig via HTTPS records. If a valid ECH Config is obtained, Xray will respect the TTL issued by the server. The query target will be the configured SNI, or the configured server domain name (if SNI is empty and the target is a domain name). - -The basic format is `"udp://1.1.1.1"`, indicating querying from UDP DNS 1.1.1.1. You can also use formats like `"https://1.1.1.1/dns-query"` (or `h2c://`), indicating querying via DOH (h2c) (replace with locally available servers for actual use). All three support modifying port numbers, e.g., `udp://1.1.1.1:53`. If omitted, defaults to 53/443 based on protocol. - -Specifically, you can use a designated domain for querying ECHConfig, in the format `"example.com+https://1.1.1.1/dns-query"`. In this way, Xray will force the use of the ECHConfig in the DNS record of `example.com` for connection. This is useful if you want to get ECHConfig from DNS but don't want to expose yourself querying the HTTPS record of this domain or publishing HTTPS records under this domain. - -> `echSockopt` : [SockoptObject](#sockoptobject) - -Adjusts the underlying socket options of the connection used when querying ECH records using DNS. - -### RealityObject - -```json -{ - "show": false, - "target": "example.com:443", - "xver": 0, - "serverNames": ["example.com", "www.example.com"], - "privateKey": "", - "minClientVer": "", - "maxClientVer": "", - "maxTimeDiff": 0, - "shortIds": ["", "0123456789abcdef"], - "mldsa65Seed": "", - "limitFallbackUpload": { - "afterBytes": 0, - "bytesPerSec": 0, - "burstBytesPerSec": 0 - }, - "limitFallbackDownload": { - "afterBytes": 0, - "bytesPerSec": 0, - "burstBytesPerSec": 0 - }, - "fingerprint": "chrome", - "serverName": "", - "password": "", - "shortId": "", - "mldsa65Verify": "", - "spiderX": "" -} -``` - -::: tip -For more information, please refer to the [REALITY Project](https://github.com/XTLS/REALITY). -::: - -::: tip -Reality only modifies TLS. Client implementation only requires slight modification of fully random session IDs and custom certificate verification, theoretically fully compatible with most TLS combinations. -::: - -> `show` : true | false - -When set to `true`, debug information is output. - -::: tip -The following are **Inbound** (**Server-side**) configurations. -::: - -> `target` : string - -Required. Format same as VLESS `fallbacks` [dest](./features/fallback.md#fallbackobject). - -Formerly named `dest`, both fields are aliases in the current version. - -If `target` supports the post-quantum key exchange algorithm X25519MLKEM768, the Reality client will also automatically use this post-quantum algorithm for key negotiation. You can check support using `xray tls ping cloudflare.com` (change URL to dest, can include port). - -The core distinguishes whether the current configuration is client or server based on the existence of this field. Do not fill it in on the client side, otherwise, it will cause identification errors. - -::: warning -To ensure effective camouflage, Xray will **directly forward** traffic that fails authentication (non-legitimate Reality requests) to `target`. -If the IP address of the `target` website is special (e.g., websites using CloudFlare CDN), it is equivalent to your server acting as a port forwarder for CloudFlare, which may cause traffic theft after being scanned. - -To prevent this, consider methods like fronting with Nginx to filter out SNIs that do not meet requirements. -Alternatively, consider configuring `limitFallbackUpload` and `limitFallbackDownload` to limit rates. -::: - -> `xver` : number - -Optional. Format same as VLESS `fallbacks` [xver](./features/fallback.md#fallbackobject). - -> `serverNames` : \[string\] - -Required. List of `serverNames` available to clients. `*` wildcard is not supported. - -Generally consistent with `target`. Actual valid values are any SNI accepted by the server (depending on the configuration of `target` itself), usually referring to the [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) of the returned certificate. - -Can contain empty value `""` representing acceptance of connections without SNI. Using this feature does not require `target` to have an IP certificate, just ensure it does not refuse connections upon receiving a Client Hello without SNI. When using this feature, the client `serverName` cannot be empty; it needs to be filled with any valid IP address as a placeholder. - -You can use `xray tls ping` to observe the server's response behavior to requests without SNI. - -> `privateKey` : string - -Required. Execute `./xray x25519` to generate. - -> `minClientVer` : string - -Optional. Minimum Xray client version, format `x.y.z`. - -> `maxClientVer` : string - -Optional. Maximum Xray client version, format `x.y.z`. - -> `maxTimeDiff` : number - -Optional. Maximum allowed time difference in milliseconds. - -> `shortIds` : \[string\] - -Required. List of `shortIds` available to clients, used to distinguish different clients. - -Format requirements see `shortId`. - -If empty value is included, client `shortId` can be empty. - -> `mldsa65Seed` : string - -Server-only. Private key used to add extra post-quantum signatures to the certificate sent to the Reality client, using ML-DSA-65 (if a quantum computer capable of breaking x25519 exists, password leakage could allow MITM; this feature prevents such future attacks). - -Use `xray mldsa65` to generate public-private key pairs. Configuring the private key on the server only adds it to certificate extensions, not affecting older clients or clients with this feature disabled. - -Note: After configuring this feature, the length of the certificate returned by `target` **must** be greater than 3500, because post-quantum signatures cause the temporary certificate returned by Reality to become larger. To prevent creating a fingerprint, the certificate returned by `target` must also be large. You can check using `xray tls ping example.com`. Also, for perfect post-quantum security, `target` also needs to support post-quantum key exchange X25519MLKEM768; support can also be checked via the previous command. - -> `limitFallbackUpload`/`limitFallbackDownload` - -::: warning -Warning: For REALITY best practice, always steal certificates from the same ASN, so you probably won't use this feature; only when you are forced to steal certificates from free CDNs like Cloudflare, to avoid your server becoming an acceleration node for others, consider enabling this feature. - -Fallback rate limiting is a fingerprint and is not recommended. If you are a panel/one-click script developer, be sure to randomize these parameters. -::: - -::: tip -`limitFallbackUpload` and `limitFallbackDownload` are optional. They limit the speed of fallback connections that fail verification. `bytesPerSec` defaults to 0, meaning disabled. - -Principle: For each unverified fallback connection, the rate limiting algorithm is enabled after transmitting `afterBytes` bytes. -Rate limiting uses a token bucket algorithm. The bucket capacity is `burstBytesPerSec`. Each byte transmitted consumes one token. Initial `burstBytesPerSec` is full. -The bucket is filled with `bytesPerSec` tokens every second until full. - -Example: `afterBytes=10485760`, `burstBytesPerSec=5242880`, `bytesPerSec=1048576` means limiting speed to 1MB/s after transmitting 15MB. If transmission pauses, after 5 seconds it can burst to 5MB/s, then revert to 1MB/s. - -Suggestion: Too large `afterBytes` and `burstBytesPerSec` will not be effective for rate limiting. Too small `bytesPerSec` and `burstBytesPerSec` are easy to detect. -Parameters should be set reasonably combined with the resource size of the stolen website. If burst is not allowed, `burstBytesPerSec` can be set to 0. -::: - -> `afterBytes` : number - -Optional. Limits the speed of fallback REALITY connections. Start limiting after transmitting specified bytes. Default is 0. - -> `bytesPerSec` : number - -Optional. Limits the speed of fallback REALITY connections. Base rate limit (bytes/second). Default 0 means rate limiting is disabled. - -> `burstBytesPerSec` : number - -Optional. Limits the speed of fallback REALITY connections. Burst rate limit (bytes/second). Effective when greater than `bytesPerSec`. - -::: tip -The following are **Outbound** (**Client-side**) configurations. -::: - -> `serverName` : string - -One of the server `serverNames`. - -Specifically, the client can set this to any IP address, and Xray will send a Client Hello without SNI extension. To use this feature, ensure server `serverNames` contains empty value `""`. - -> `fingerprint` : string - -Required. Same as [TLSObject](#tlsobject). Note: Using `unsafe` to disable uTLS is not supported here, because the REALITY protocol implementation uses this library to manipulate underlying TLS parameters. - -> `shortId` : string - -One of the server `shortIds`. - -Length is 8 bytes, i.e., 16 hexadecimal characters (0~f). Can be less than 16; the core will automatically pad with 0s at the end, but the count must be **even** (since one byte has 2 hex digits). - -E.g., `aa1234` will be auto-padded to `aa12340000000000`, but `aaa1234` will cause an error. - -0 is also even, so if server `shortIds` contains empty value `""`, client can also be empty. - -> `password` : string - -Required. Public key corresponding to the server private key. Generated using `./xray x25519 -i "server private key"`. Formerly `publicKey`, renamed to prevent misunderstanding (this is indeed an x25519 public key in status, but in Reality design, it is held by the client and cannot be public). - -> `mldsa65Verify` - -Optional. Public key used for mldsa65 signature verification. When non-empty, use this public key to check the certificate returned by the server. See description of `"mldsa65Seed"` for details. - -> `spiderX` : string - -Initial path and parameters for the spider. It is recommended that each client be different. - -#### CertificateObject - -```json -{ - "ocspStapling": 0, - "oneTimeLoading": false, - "usage": "encipherment", - "buildChain": false, - "certificateFile": "/path/to/certificate.crt", - "keyFile": "/path/to/key.key", - "certificate": [ - "--BEGIN CERTIFICATE--", - "MIICwDCCAaigAwIBAgIRAO16JMdESAuHidFYJAR/7kAwDQYJKoZIhvcNAQELBQAw", - "ADAeFw0xODA0MTAxMzU1MTdaFw0xODA0MTAxNTU1MTdaMAAwggEiMA0GCSqGSIb3", - "DQEBAQUAA4IBDwAwggEKAoIBAQCs2PX0fFSCjOemmdm9UbOvcLctF94Ox4BpSfJ+", - "3lJHwZbvnOFuo56WhQJWrclKoImp/c9veL1J4Bbtam3sW3APkZVEK9UxRQ57HQuw", - "OzhV0FD20/0YELou85TwnkTw5l9GVCXT02NG+pGlYsFrxesUHpojdl8tIcn113M5", - "pypgDPVmPeeORRf7nseMC6GhvXYM4txJPyenohwegl8DZ6OE5FkSVR5wFQtAhbON", - "OAkIVVmw002K2J6pitPuJGOka9PxcCVWhko/W+JCGapcC7O74palwBUuXE1iH+Jp", - "noPjGp4qE2ognW3WH/sgQ+rvo20eXb9Um1steaYY8xlxgBsXAgMBAAGjNTAzMA4G", - "A1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA", - "MA0GCSqGSIb3DQEBCwUAA4IBAQBUd9sGKYemzwPnxtw/vzkV8Q32NILEMlPVqeJU", - "7UxVgIODBV6A1b3tOUoktuhmgSSaQxjhYbFAVTD+LUglMUCxNbj56luBRlLLQWo+", - "9BUhC/ow393tLmqKcB59qNcwbZER6XT5POYwcaKM75QVqhCJVHJNb1zSEE7Co7iO", - "6wIan3lFyjBfYlBEz5vyRWQNIwKfdh5cK1yAu13xGENwmtlSTHiwbjBLXfk+0A/8", - "r/2s+sCYUkGZHhj8xY7bJ1zg0FRalP5LrqY+r6BckT1QPDIQKYy615j1LpOtwZe/", - "d4q7MD/dkzRDsch7t2cIjM/PYeMuzh87admSyL6hdtK0Nm/Q", - "--END CERTIFICATE--" - ], - "key": [ - "--BEGIN RSA PRIVATE KEY--", - "MIIEowIBAAKCAQEArNj19HxUgoznppnZvVGzr3C3LRfeDseAaUnyft5SR8GW75zh", - "bqOeloUCVq3JSqCJqf3Pb3i9SeAW7Wpt7FtwD5GVRCvVMUUOex0LsDs4VdBQ9tP9", - "GBC6LvOU8J5E8OZfRlQl09NjRvqRpWLBa8XrFB6aI3ZfLSHJ9ddzOacqYAz1Zj3n", - "jkUX+57HjAuhob12DOLcST8np6IcHoJfA2ejhORZElUecBULQIWzjTgJCFVZsNNN", - "itieqYrT7iRjpGvT8XAlVoZKP1viQhmqXAuzu+KWpcAVLlxNYh/iaZ6D4xqeKhNq", - "IJ1t1h/7IEPq76NtHl2/VJtbLXmmGPMZcYAbFwIDAQABAoIBAFCgG4phfGIxK9Uw", - "qrp+o9xQLYGhQnmOYb27OpwnRCYojSlT+mvLcqwvevnHsr9WxyA+PkZ3AYS2PLue", - "C4xW0pzQgdn8wENtPOX8lHkuBocw1rNsCwDwvIguIuliSjI8o3CAy+xVDFgNhWap", - "/CMzfQYziB7GlnrM6hH838iiy0dlv4I/HKk+3/YlSYQEvnFokTf7HxbDDmznkJTM", - "aPKZ5qbnV+4AcQfcLYJ8QE0ViJ8dVZ7RLwIf7+SG0b0bqloti4+oQXqGtiESUwEW", - "/Wzi7oyCbFJoPsFWp1P5+wD7jAGpAd9lPIwPahdr1wl6VwIx9W0XYjoZn71AEaw4", - "bK4xUXECgYEA3g2o9WqyrhYSax3pGEdvV2qN0VQhw7Xe+jyy98CELOO2DNbB9QNJ", - "8cSSU/PjkxQlgbOJc8DEprdMldN5xI/srlsbQWCj72wXxXnVnh991bI2clwt7oYi", - "pcGZwzCrJyFL+QaZmYzLxkxYl1tCiiuqLm+EkjxCWKTX/kKEFb6rtnMCgYEAx0WR", - "L8Uue3lXxhXRdBS5QRTBNklkSxtU+2yyXRpvFa7Qam+GghJs5RKfJ9lTvjfM/PxG", - "3vhuBliWQOKQbm1ZGLbgGBM505EOP7DikUmH/kzKxIeRo4l64mioKdDwK/4CZtS7", - "az0Lq3eS6bq11qL4mEdE6Gn/Y+sqB83GHZYju80CgYABFm4KbbBcW+1RKv9WSBtK", - "gVIagV/89moWLa/uuLmtApyEqZSfn5mAHqdc0+f8c2/Pl9KHh50u99zfKv8AsHfH", - "TtjuVAvZg10GcZdTQ/I41ruficYL0gpfZ3haVWWxNl+J47di4iapXPxeGWtVA+u8", - "eH1cvgDRMFWCgE7nUFzE8wKBgGndUomfZtdgGrp4ouLZk6W4ogD2MpsYNSixkXyW", - "64cIbV7uSvZVVZbJMtaXxb6bpIKOgBQ6xTEH5SMpenPAEgJoPVts816rhHdfwK5Q", - "8zetklegckYAZtFbqmM0xjOI6bu5rqwFLWr1xo33jF0wDYPQ8RHMJkruB1FIB8V2", - "GxvNAoGBAM4g2z8NTPMqX+8IBGkGgqmcYuRQxd3cs7LOSEjF9hPy1it2ZFe/yUKq", - "ePa2E8osffK5LBkFzhyQb0WrGC9ijM9E6rv10gyuNjlwXdFJcdqVamxwPUBtxRJR", - "cYTY2HRkJXDdtT0Bkc3josE6UUDvwMpO0CfAETQPto1tjNEDhQhT", - "--END RSA PRIVATE KEY--" - ] -} -``` - -Server certificate, hot reloaded every 3600 seconds (i.e., one hour). - -> `ocspStapling`: number - -OCSP stapling update interval in seconds, default is 0. Any non-zero value enables OCSP stapling and overrides the default 3600-second certificate hot reload time (executes OCSP stapling while reloading). - -> `oneTimeLoading`: true | false - -Load only once, default `false`. When set to `true`, certificate hot reloading and OCSP stapling are disabled. - -> `usage`: "encipherment" | "verify" | "issue" - -Certificate usage, default value is `"encipherment"`. - -- `"encipherment"`: Certificate is used for TLS authentication and encryption. -- `"verify"`: Certificate is used to verify remote TLS certificates. When using this item, the current certificate must be a CA certificate. -- `"issue"`: Certificate is used to issue other certificates. When using this item, the current certificate must be a CA certificate. - -::: tip TIP 1 -On Windows platforms, self-signed CA certificates can be installed into the system to verify remote TLS certificates. -::: - -::: tip TIP 2 -When there is a new client request, assuming the specified `serverName` is `"xray.com"`, Xray will first look for a valid certificate for `"xray.com"` in the certificate list. If not found, it will use any certificate with `usage` `"issue"` to issue a certificate valid for `"xray.com"` with a validity period of one hour. The new certificate is added to the certificate list for future use. -::: - -::: tip TIP 3 -When both `certificateFile` and `certificate` are specified, Xray prefers `certificateFile`. Same for `keyFile` and `key`. -::: - -::: tip TIP 4 -When `usage` is `"verify"`, `keyFile` and `key` can both be empty. -::: - -::: tip TIP 5 -Use `xray tls cert` to generate self-signed CA certificates. -::: - -::: tip TIP 6 -If you already own a domain, you can use tools like [acme.sh](https://github.com/acmesh-official/acme.sh) to easily get free third-party certificates. -::: - -> `buildChain`: true | false - -Only effective when certificate usage is `issue`. If `true`, embed the CA certificate into the certificate chain when issuing certificates. - -::: tip TIP 1 -Root certificates should not be embedded in the certificate chain. This option is only suitable when the signing CA certificate is an intermediate certificate. -::: - -> `certificateFile`: string - -Certificate file path. If generated using OpenSSL, extension is .crt. - -> `certificate`: \[ string \] - -An array of strings representing certificate content, format as shown in the example. Choose one between `certificate` and `certificateFile`. - -> `keyFile`: string - -Key file path. If generated using OpenSSL, extension is .key. Password-protected key files are not supported currently. - -> `key`: \[ string \] - -An array of strings representing key content, format as shown in the example. Choose one between `key` and `keyFile`. - -### SockoptObject - -```json -{ - "mark": 0, - "tcpMaxSeg": 1440, - "tcpFastOpen": false, - "tproxy": "off", - "domainStrategy": "AsIs", - "happyEyeballs": {}, - "dialerProxy": "", - "acceptProxyProtocol": false, - "tcpKeepAliveInterval": 0, - "tcpKeepAliveIdle": 300, - "tcpUserTimeout": 10000, - "tcpcongestion": "bbr", - "interface": "wg0", - "V6Only": false, - "tcpWindowClamp": 600, - "tcpMptcp": false, - "addressPortStrategy": "", - "customSockopt": [] -} -``` - -> `mark`: number - -An integer. When non-zero, mark the outbound connection with this value using SO_MARK. - -- Only applies to Linux systems. -- Requires CAP_NET_ADMIN permission. - -> `tcpMaxSeg`: number - -Used to set the Maximum Segment Size (MSS) for TCP packets. - -> `tcpFastOpen`: true | false | number - -Whether to enable [TCP Fast Open](https://en.wikipedia.org/wiki/TCP_Fast_Open). - -When set to `true` or a `positive integer`, TFO is enabled; when `false` or `negative`, TFO is forced disabled; when absent or `0`, system default is used. Can be used for inbound/outbound. - -- Only available in the following (or newer) OS versions: - - Linux 3.16: Requires setting kernel parameter `net.ipv4.tcp_fastopen`. This parameter is a bitmap: `0x1` allows client to enable, `0x2` allows server to enable; default is `0x1`. If server needs to enable TFO, set this to `0x3`. - - ~~Windows 10 (1607)~~ (Implementation incorrect) - - Mac OS 10.11 / iOS 9 (Needs testing) - - FreeBSD 10.3 (Server) / 12.0 (Client): Requires kernel parameters `net.inet.tcp.fastopen.server_enabled` and `net.inet.tcp.fastopen.client_enabled` set to `1`. (Needs testing) - -- For Inbound, the `positive integer` set here represents the [limit of pending TFO connection requests](https://tools.ietf.org/html/rfc7413#section-5.1). **Note: Not all OSs support setting this here**: - - Linux / FreeBSD: The `positive integer` here represents the limit. Max acceptable value is 2147483647. If `true`, it takes `256`. Note on Linux, `net.core.somaxconn` limits this value. If exceeding `somaxconn`, increase `somaxconn` as well. - - Mac OS: `true` or `positive integer` only enables TFO. The limit needs to be set via kernel parameter `net.inet.tcp.fastopen_backlog`. - - Windows: `true` or `positive integer` only enables TFO. - -- For Outbound, setting to `true` or `positive integer` only enables TFO on any OS. - -> `tproxy`: "redirect" | "tproxy" | "off" - -Whether to enable transparent proxy (Linux only). - -- `"redirect"`: Use Redirect mode transparent proxy. Supports all IPv4/6 TCP connections. -- `"tproxy"`: Use TProxy mode transparent proxy. Supports all IPv4/6 TCP and UDP connections. -- `"off"`: Disable transparent proxy. - -Transparent proxy requires Root or `CAP_NET_ADMIN` permission. - -::: danger -When `followRedirect` is `true` in [Dokodemo-door](./inbounds/tunnel.md), and `tproxy` in Sockopt settings is empty, the value of `tproxy` in Sockopt settings will be set to `"redirect"`. -::: - -> `domainStrategy`: "AsIs"
-> "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
-> "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4" - -Default value `"AsIs"`. - -When the target address is a domain name, configure the value to control the Outbound connection behavior: - -- `"AsIs"`: Xray does no special handling of domains. Finally, Xray uses Go's built-in Dial to initiate connection. Priority is fixed to RFC6724 default (will not follow gai.conf etc.), usually IPv6 preferred. -- Other values: Use Xray-core [Built-in DNS Server](dns.md) for resolution. If no DNSObject exists, system DNS is used. If multiple IPs match, the core randomly selects one as the target IP. -- `"IPv4"`: Attempt to connect using only IPv4. -- `"IPv4v6"`: Attempt to connect using IPv4 or IPv6, but use IPv4 for dual-stack domains. (v4v6 swapped is analogous). -- When `"queryStrategy"` is set in built-in DNS, actual behavior intersects with this option. Only IP types included in both will be resolved. E.g., `"queryStrategy": "UseIPv4"` + `"domainStrategy": "UseIP"` is effectively `"domainStrategy": "UseIPv4"`. -- `"Use"` prefix: If resolution result doesn't meet requirements (e.g., domain only has IPv4 but used UseIPv6), fallback to AsIs. -- `"Force"` prefix: If resolution result doesn't meet requirements, connection fails. - -::: tip TIP -When using `"UseIP"` or `"ForceIP"` modes, and `sendThrough` is specified in [Outbound Connection Configuration](outbound.md#outboundobject), the core automatically judges required IP type (IPv4 or IPv6) based on `sendThrough`. If a single IP type is manually specified (e.g., UseIPv4) but mismatches `sendThrough` local address, connection fails. -::: - -::: danger -Enabling this feature with improper configuration may cause infinite loops. - -TL;DR: Connecting to server requires waiting for DNS result; finishing DNS query requires connecting to server. - -> 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`. -4. **Improper** routing rules cause `proxy.com` to proxy the query sent in step 3. -5. Xray attempts to establish another TCP connection to `proxy.com`. -6. Before establishing, query `proxy.com` via built-in DNS. -7. Built-in DNS reuses connection from step 3 to send query. -8. Problem: Connection in step 3 waits for query result in step 7; query in step 7 waits for connection in step 3 to fully establish. -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.~~ - -Therefore, inexperienced users are **not recommended** to use this feature unauthorized. -::: - -> `dialerProxy`: "" - -An outbound proxy identifier. When not empty, connection is made using specified outbound. Used for chain forwarding supporting underlying transports. - -::: danger -Incompatible with ProxySettingsObject.Tag. -::: - -> `acceptProxyProtocol`: true | false - -Inbound only. Indicates whether to accept PROXY protocol. - -[PROXY protocol](https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) is for passing real source IP and port. **Ignore if you don't understand it**. - -Common reverse proxies (HAProxy, Nginx) can be configured to send it. VLESS fallbacks xver can also send it. - -When `true`, requester must send PROXY protocol v1 or v2 after bottom-layer TCP establishment, otherwise connection closes. - -> `tcpKeepAliveIdle`: number - -TCP idle time threshold in seconds. Keep-Alive probes start after connection is idle for this duration. - -For outbound, Xray uses Chrome defaults (idle & interval both 45s). Setting this or `tcpKeepAliveInterval` to negative disables default keepalive; positive overrides default. - -For inbound, Keep-Alive is disabled by default. Enabled if either this or `tcpKeepAliveInterval` is non-zero. If only one is set, the other follows OS settings. - -> `tcpKeepAliveInterval`: number - -Interval between Keep-Alive packets in seconds after TCP enters Keep-Alive state. See above for behavior. - -> `tcpUserTimeout`: number - -In milliseconds. Details: https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md - -> `tcpcongestion`: "" - -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. -::: - -> `interface`: "" - -Bind outbound network interface name. Supports Linux / iOS / Mac OS / Windows. - -> `V6Only`: true | false - -When `true`, listening on `::` only accepts IPv6 connections. Linux only. - -> `tcpWindowClamp`: number - -Bind advertised window size to this value. Kernel picks max between this and SOCK_MIN_RCVBUF/2. - -> `tcpMptcp`: true | false - -Default `false`. When `true`, enables [Multipath TCP](https://en.wikipedia.org/wiki/Multipath_TCP). Client-only parameter, as golang 1.24+ enables MPTCP by default on listen. -Currently only supports Linux, requires Kernel 5.6+. - -> `tcpNoDelay`: true | false - -Option removed as golang enables TCP no delay by default. To disable, use customSockopt. - -> `addressPortStrategy`: "none" | "SrvPortOnly" | "SrvAddressOnly" | "SrvPortAndAddress" | "TxtPortOnly" | "TxtAddressOnly" | "TxtPortAndAddress" - -Use SRV or TXT records to specify target address/port for outbound. Default `none` (off). - -Query goes through system DNS, not Xray built-in DNS. Domain queried is the outbound domain. If query fails, request proceeds with original address/port. - -`Srv` prefix: Query SRV record (standard format). `Txt` prefix: Query TXT record (format like `127.0.0.1:80`). - -`PortOnly`: Reset port only. `AddressOnly`: Reset address only. `PortAndAddress`: Reset both. - -Effective before sockopt `domainStrategy` resolution. After reset, still resolves per `domainStrategy` (if any), but ineffective if Freedom `domainStrategy` is set to resolve to IP beforehand. - -PS: If normal domain traffic comes to AsIs Freedom outbound, it attempts resolution and reset here. E.g., core queries SRV record for google.com and resets target accordingly. - -> `customSockopt`: [] - -Array for advanced users to specify any sockopt. Theoretically covers all connection settings. Supports Linux, Windows, Darwin. Example equivalent to `"tcpcongestion": "bbr"`: - -Ensure you understand Socket programming. - -```json -"customSockopt": [ - { - "system": "linux", - "type": "str", - "level":"6", - "opt": "13", - "value": "bbr" - } -] -``` - -> `system`: "" - -Optional. Target system. Skipped if mismatch. Options: `linux`, `windows`, `darwin` (lowercase). Executes if empty. - -> `type`: "" - -Required. Type, `int` or `str`. - -> `level`: "" - -Optional. Protocol level. Default 6 (TCP). - -> `opt`: "" - -Option name in decimal (Example TCP_CONGESTION 0xd is 13). - -> `value`: "" - -Value to set. Example sets bbr. -Use decimal number if type is int. - -> `happyEyeballs`: [HappyEyeballsObject](#happyeyeballsobject) - -RFC-8305 Happy Eyeballs implementation, TCP only. Races target domains and selects first success. Only effective when `Sockopt.domainStrategy` is not `AsIs`. - -Note: `UseIPv4v6` / `ForceIPv4v6` reduces available IPs to IPv4 only, falling back to IPv6 query only on failure. Not recommended. Suggest `UseIP` / `ForceIP` with `HappyEyeballs.interleave`. - -::: warning -Do not use `Freedom` outbound's `domainStrategy` with this, as `Sockopt` will only see the replaced IP. -::: - -#### HappyEyeballsObject - -```json -"happyEyeballs": { - "tryDelayMs": 250, - "prioritizeIPv6": false, - "interleave": 1, - "maxConcurrentTry": 4 -} -``` - -> `tryDelayMs`: number - -Interval between race requests in ms. Default 0 (disabled). Recommended 250. - -> `prioritizeIPv6`: bool - -Whether first IP is IPv6 when sorting. Default `false` (IPv4 first). - -> `interleave`: number - -"First Address Family count" in RFC-8305. Default 1. Defines interleaving behavior for sorting IP versions. - -E.g., waiting IP queue sorted as 46464646 (set to 1), 44664466 (set to 2). - -> `maxConcurrentTry`: number - -Max concurrent attempts. Prevents core from making massive connections if many IPs resolve but fail. Default 4. Set to 0 to disable happyEyeballs. - -### FinalMaskObject - -FinalMask applies a final layer of obfuscation to the traffic after the core has processed transport layer encryption, including TLS/REALITY. Currently, only UDP is supported. - -```json -{ - "tcp": [ - { - "type": "", - "settings": {} - } - ], - "udp": [ - { - "type": "", - "settings": {} - } - ], - "quicParams": { - "congestion": "force-brutal", - "debug": false, - "brutalUp": "60 mbps", - "brutalDown": 0, - "udpHop": { - "ports": "20000-50000", - "interval": "5-10" - }, - "initStreamReceiveWindow": 8388608, - "maxStreamReceiveWindow": 8388608, - "initConnectionReceiveWindow": 20971520, - "maxConnectionReceiveWindow": 20971520, - "maxIdleTimeout": 30, - "keepAlivePeriod": 0, - "disablePathMTUDiscovery": false, - "maxIncomingStreams": 1024 - } -} -``` - -> `tcp[n].type`: header-custom | fragment | sudoku - -The first element in the array is the outermost camouflage. - -Used in conjunction with raw | httpupgarde | websocket | gRPC | xhttp transport layers. - -`header-custom`: - -`fragment`: - -`sudoku`: - -> `tcp[n].settings`: header-custom | fragment | sudoku - -#### header-custom - -```json -{ - "clients": [ - [ - { - "delay": 0, - "rand": 0, - "randRange": "0-255", - "type": "", - "packet": [] - } - ] - ], - "servers": [ - [ - { - "delay": 0, - "rand": 0, - "randRange": "0-255", - "type": "", - "packet": [] - } - ] - ], - "errors": [ - [ - { - "delay": 0, - "rand": 0, - "randRange": "0-255", - "type": "", - "packet": [] - } - ] - ] -} -``` - -`clients[n][m].delay`: The unit is milliseconds; a value of 0 indicates that the packet was previously sent in a fragmented manner. - -`clients[n][m].rand`: Adds a specified length of random bytes, which conflicts with `packet`. - -`clients[n][m].randRange`: Random byte range, default 0-255. - -`clients[n][m].type`: The `packet` type can be `array | str | hex | base64`, with the default being array. - -`clients[n][m].packet`: Adding fixed data conflicts with `rand`. - -#### fragment - -```json -{ - "packets": "tlshello", - "length": "100-200", - "delay": "10-20", - "maxSplit": "3-6" -} -``` - -#### sudoku - -```json -{ - "password": "", - "ascii": "", - - "customTable": "", // custom_table in official docs - "customTables": [""], // custom_tables in official docs - - "paddingMin": 0, // padding_min in official docs - "paddingMax": 0 // padding_max in official docs -} -``` - -See [official documentation](https://github.com/SUDOKU-ASCII/sudoku/blob/main/configs/README.md) for field descriptions. - -> `udp[n].type`: header-custom | header-dns | header-dtls | header-srtp | header-utp | header-wechat | header-wireguard | mkcp-original | mkcp-aes128gcm | noise | salamander | sudoku | xdns | xicmp - -The first element in the array is the outermost camouflage. - -Used in conjunction with raw udp | kcp | hysteria | xhttp h3 transport layers. - -`header-custom`: Always merge packets into the data packet header. - -`header-dns`: Original mKCP DNS obfuscation. Some campus networks allow DNS queries without login, add DNS header to KCP. - -`header-dtls`: Original mKCP DTLS obfuscation. Obfuscates as DTLS 1.2 packets. No additional configuration required. - -`header-srtp`: Original mKCP SRTP obfuscation. Obfuscates as SRTP packets, will be recognized as video call data (e.g., FaceTime). No additional configuration required. - -`header-utp`: Original mKCP uTP obfuscation. Obfuscates as uTP packets, will be recognized as BT download data. No additional configuration required. - -`header-wechat`: Original mKCP WeChat Video obfuscation. Obfuscates as WeChat video call data. No additional configuration required. - -`header-wireguard`: Original mKCP WireGuard obfuscation. Obfuscates as WireGuard packets. (Not the real WireGuard protocol) No additional configuration required. - -`mkcp-original`: The simple obfuscation that was previously applied by default in mKCP. You may need to configure this to connect to legacy mKCP servers. No additional configuration required. - -`mkcp-aes128gcm`: Corresponds to the original mKCP `seed` feature. Uses AES-128-GCM for obfuscation. - -`noise`: Noise sent before data is transmitted. - -`salamander`: Salamander obfuscation (from Hysteria2). - -`sudoku`: - -`xdns`: Utilizes DNS queries to transport data (similar to DNSTT). It performs standard DNS TXT queries to transport the payload. Due to technical limitations, the resulting MTU is very small, making it incompatible with QUIC; it is recommended to use it with mKCP. Recommended MTU values: Client 130, Server 900. - -`domain` is the domain name used for queries. Since the queries performed are standard, they can be forwarded through any UDP DNS server, although efficiency may be very suboptimal. To use this feature, the server needs to listen on port 53, and the proxy protocol should direct the target to a DNS server (e.g., 8.8.8.8:53). Additionally, you must own the domain specified in `domain` and point its NS record to your server. - -For example, if you own example.com, then you can set an A record for a.example.com pointing to the IP address, set an NS record for t.example.com pointing to t.example.com, and ultimately use t.example.com. The A record cannot be a subdomain of an NS record. - -`xicmp`: It requires at least `CAP_NET_RAW` permissions and must be at the outermost level, i.e., the first element in the array. It cannot be used with `udpHop` or `dialerProxy`. - -> `udp[n].settings`: header-custom | header-dns | mkcp-aes128gcm | noise | salamander | sudoku | xdns | xicmp - -#### header-custom - -```json -{ - "client": [ - { - "rand": 0, - "randRange": "0-255", - "type": "", - "packet": [] - } - ], - "server": [ - { - "rand": 0, - "randRange": "0-255", - "type": "", - "packet": [] - } - ] -} -``` - -`client[n].rand`: Adds a specified length of random bytes, which conflicts with `packet`. - -`client[n].randRange`: Random byte range, default 0-255. - -`client[n].type`: The `packet` type can be `array | str | hex | base64`, with the default being array. - -`client[n].packet`: Adding fixed data conflicts with `rand`. - -#### header-dns - -```json -{ - "domain": "www.example.com" -} -``` - -#### mkcp-aes128gcm - -```json -{ - "password": "your-password" -} -``` - -#### noise - -```json -{ - "reset": 0, - "noise": [ - { - "rand": "1-8192", - "randRange": "0-255", - "type": "", - "packet": [], - "delay": "10-20" - } - ] -} -``` - -`noise[n].rand`: Adds random or specified length of random bytes, which conflicts with `packet`. - -`noise[n].randRange`: Random byte range, default 0-255. - -`noise[n].type`: The `packet` type can be `array | str | hex | base64`, with the default being array. - -`noise[n].packet`: Adding fixed data conflicts with `rand`. - -`noise[n].delay`: The unit is milliseconds. After sending one noise signal, a specified time is delayed before sending the next one. - -#### salamander - -```json -{ - "password": "your-password" -} -``` - -#### sudoku - -```json -{ - "password": "", - "ascii": "", - - "customTable": "", - "customTables": [""], - - "paddingMin": 0, - "paddingMax": 0 -} -``` - -Same as the TCP version. - -#### xdns - -```json -{ - "domain": "www.example.com" -} -``` - -#### xicmp - -```json -{ - "listenIp": "0.0.0.0", - "id": 0 -} -``` - -`listenIp`: The IP address to listen on. - -`id`: If there are multiple clients under the same IP address, it is recommended that the server keep it at 0. - -> `quicParams`: [quicParamsObject](#quicParams) - -#### quicParams - -```json -{ - "congestion": "force-brutal", - "debug": false, - "brutalUp": "60 mbps", - "brutalDown": 0, - "udpHop": { - "ports": "20000-50000", - "interval": "5-10" - }, - "initStreamReceiveWindow": 8388608, - "maxStreamReceiveWindow": 8388608, - "initConnectionReceiveWindow": 20971520, - "maxConnectionReceiveWindow": 20971520, - "maxIdleTimeout": 30, - "keepAlivePeriod": 0, - "disablePathMTUDiscovery": false, - "maxIncomingStreams": 1024 -} -``` - -Used for QUIC configuration tuning of XHTTP H3 and Hysteria. - -> `congestion`: reno | bbr | brutal | force-brutal - -Congestion control algorithm. Hysteria defaults to `brutal`, XHTTP H3 defaults to `bbr`. - -`reno`/`bbr`: Well-known algorithms. - -`brutal`: Negotiates a fixed packet sending rate with the peer or falls back to BBR. Only supported with Hysteria transport (since XHTTP has no negotiation mechanism). - -`force-brutal`: Same as `brutal`, but forces upstream to use the `brutalUp` fixed packet sending rate, ignoring peer negotiation. - -> `debug`: false | true - -Enable bbr/brutal congestion control logging. - -> `brutalUp`: string - -> `brutalDown`: string - -Upload/Download rate limits. Default is 0. - -The format is user-friendly and supports various common bit-per-second notations, including `1000000`, `100kb`, `20 mb`, `100 mbps`, `1g`, `1 tbps`, etc. It is case-insensitive, and spaces between the number and unit are optional. If no unit is specified, it defaults to bps (bits per second). It cannot be lower than 65535 bps. - -The negotiation behavior is consistent with Hysteria brutal: - -The server's value limits the maximum Brutal mode rate that the client can choose. 0 means no limit on the client. - -If the client sets this to 0, it uses BBR mode. If not 0, it uses Brutal mode, subject to the server's limit. - -Note relativity: Server upload is client download, and server download is client upload. - -> `udpHop`: {"ports": string, "interval": number} - -UDP port hopping configuration. - -`ports` is the port range for hopping. It can be a numeric string, such as `"1234"`; or a numeric range, such as `"1145-1919"` (indicating ports 1145 to 1919, totaling 775 ports). Commas can be used for segmentation, such as `11,13,15-17` (indicating port 11, port 13, and ports 15 to 17, totaling 5 ports). - -`interval` is the port hopping interval in seconds. Minimum is 5, default is 30 seconds. - -> `initStreamReceiveWindow`: number - -> `maxStreamReceiveWindow`: number - -> `initConnectionReceiveWindow`: number - -> `maxConnectionReceiveWindow`: number - -These four are specific QUIC window parameters. **Unless you fully understand what you are doing, it is not recommended to modify these values.** If you must modify them, it is recommended to keep the ratio of the stream receive window to the connection receive window at 2:5. - -> `maxIdleTimeout`: number - -Maximum idle timeout (seconds). The server will close the connection if no data is received from the client for this duration. Range: 4~120 seconds. Default: 30 seconds. - -> `keepAlivePeriod`: number - -QUIC KeepAlive interval (seconds). Range: 2~60 seconds. Disabled by default. - -> `disablePathMTUDiscovery`: bool - -Whether to disable Path MTU Discovery. - -In other implementations, !linux && !windows && !darwin OS are forcibly disabled, while in xray it is not mandatory. If your OS is not (linux || windows || darwin), you may need to disable it manually. - -> `maxIncomingStreams`: number - -Server-side parameters, if set, must not be less than 8. +Configuration related to low-level network behavior. diff --git a/docs/en/config/transports/finalmask.md b/docs/en/config/transports/finalmask.md new file mode 100644 index 00000000..5a7df9c7 --- /dev/null +++ b/docs/en/config/transports/finalmask.md @@ -0,0 +1,404 @@ +# FinalMask + +FinalMask performs the last stage of traffic obfuscation after the core has already processed transport-layer security, including TLS and REALITY. + +It can be used for multiple kinds of TCP and UDP camouflage, as well as QUIC-related parameter tuning. + +## FinalMaskObject + +`FinalMaskObject` corresponds to the `finalmask` item in [`StreamSettingsObject`](../transport.md#streamsettingsobject). + +```json +{ + // outbound example; also applies to inbound + "outbounds": [ + { + // ... + "streamSettings": { + "finalmask": { + // [!code focus:30] + "tcp": [ + { + "type": "", + "settings": {} + } + ], + "udp": [ + { + "type": "", + "settings": {} + } + ], + "quicParams": { + "congestion": "force-brutal", + "debug": false, + "brutalUp": "60 mbps", + "brutalDown": 0, + "udpHop": { + "ports": "20000-50000", + "interval": "5-10" + }, + "initStreamReceiveWindow": 8388608, + "maxStreamReceiveWindow": 8388608, + "initConnectionReceiveWindow": 20971520, + "maxConnectionReceiveWindow": 20971520, + "maxIdleTimeout": 30, + "keepAlivePeriod": 0, + "disablePathMTUDiscovery": false, + "maxIncomingStreams": 1024 + } + } + } + } + ] +} +``` + +> `tcp[n].type`: header-custom | fragment | sudoku + +The first item in the array is the outermost camouflage layer. + +Used together with `raw`, `httpupgrade`, `websocket`, `grpc`, and `xhttp`. + +`header-custom`: + +`fragment`: + +`sudoku`: + +> `tcp[n].settings`: header-custom | fragment | sudoku + +### header-custom + +```json +{ + "clients": [ + [ + { + "delay": 0, + "rand": 0, + "randRange": "0-255", + "type": "", + "packet": [] + } + ] + ], + "servers": [ + [ + { + "delay": 0, + "rand": 0, + "randRange": "0-255", + "type": "", + "packet": [] + } + ] + ], + "errors": [ + [ + { + "delay": 0, + "rand": 0, + "randRange": "0-255", + "type": "", + "packet": [] + } + ] + ] +} +``` + +`clients[n][m].delay`: delay in milliseconds. When it is `0`, the data is sent together with the previous packet. + +`clients[n][m].rand`: adds a specified number of random bytes. Conflicts with `packet`. + +`clients[n][m].randRange`: range of random-byte values. The default is `0-255`. + +`clients[n][m].type`: the type of `packet`. Supported values are `array`, `str`, `hex`, and `base64`. The default is `array`. + +`clients[n][m].packet`: adds fixed data. Conflicts with `rand`. + +### fragment + +```json +{ + "packets": "tlshello", + "length": "100-200", + "delay": "10-20", + "maxSplit": "3-6" +} +``` + +### sudoku + +```json +{ + "password": "", + "ascii": "", + + "customTable": "", // field name is custom_table in the upstream documentation + "customTables": [""], // field name is custom_tables in the upstream documentation + + "paddingMin": 0, // field name is padding_min in the upstream documentation + "paddingMax": 0 // field name is padding_max in the upstream documentation +} +``` + +For the meaning of these fields, see the [upstream documentation](https://github.com/SUDOKU-ASCII/sudoku/blob/main/configs/README.md). + +> `udp[n].type`: header-custom | header-dns | header-dtls | header-srtp | header-utp | header-wechat | header-wireguard | mkcp-original | mkcp-aes128gcm | noise | salamander | sudoku | xdns | xicmp + +The first item in the array is the outermost camouflage layer. + +Used together with `raw` UDP, `kcp`, `hysteria`, and `xhttp` H3. + +`header-custom`: always prepended to the packet as a combined header. + +`header-dns`: the old mKCP DNS camouflage. Some campus networks permit DNS requests before login, so this adds a DNS header to KCP. + +`header-dtls`: the old mKCP DTLS camouflage. It imitates DTLS 1.2 packets. No extra settings. + +`header-srtp`: the old mKCP SRTP camouflage. It imitates SRTP packets and tends to look like video-call traffic such as FaceTime. No extra settings. + +`header-utp`: the old mKCP uTP camouflage. It imitates uTP packets and tends to look like BitTorrent traffic. No extra settings. + +`header-wechat`: the old mKCP WeChat Video camouflage. It imitates WeChat video-call packets. No extra settings. + +`header-wireguard`: the old mKCP WireGuard camouflage. It imitates WireGuard packets, though it is not the real WireGuard protocol. No extra settings. + +`mkcp-original`: the simple obfuscation that used to be the default in mKCP. You may need it to connect to older mKCP servers. No extra settings. + +`mkcp-aes128gcm`: the old mKCP `seed` feature. It uses AES-128-GCM for obfuscation. + +`noise`: noise sent before the actual payload. + +`salamander`: Salamander obfuscation from Hysteria2. + +`sudoku`: + +`xdns`: transmits data through DNS queries in a way similar to DNSTT. It performs standard DNS TXT queries to carry payload. + +Because of technical limitations, the effective MTU is very small and QUIC is not usable. It is recommended to pair it with mKCP. Recommended MTU values are 130 on the client and 900 on the server. + +Since the queries are standard DNS requests, they can be forwarded by any UDP DNS server, although the efficiency may be very poor. + +To use this feature, the server must listen on port 53, the proxy protocol must target a DNS server such as `8.8.8.8:53`, and you must own the `domain` used by xdns and point its NS record to the server. + +For example, if you own `example.com`, create an A record like `a.example.com` pointing to your server IP, then create an NS record like `t.example.com` pointing to `t.example.com`, and use `t.example.com` as the domain. The A record must not be a subdomain of the NS record. + +`xicmp`: requires at least `CAP_NET_RAW`, must be the outermost layer, which means the first array element, and cannot be used together with `udpHop` or `dialerProxy`. + +> `udp[n].settings`: header-custom | header-dns | mkcp-aes128gcm | noise | salamander | sudoku | xdns | xicmp + +### header-custom + +```json +{ + "client": [ + { + "rand": 0, + "randRange": "0-255", + "type": "", + "packet": [] + } + ], + "server": [ + { + "rand": 0, + "randRange": "0-255", + "type": "", + "packet": [] + } + ] +} +``` + +`client[n].rand`: adds a specified number of random bytes. Conflicts with `packet`. + +`client[n].randRange`: range of random-byte values. The default is `0-255`. + +`client[n].type`: the type of `packet`. Supported values are `array`, `str`, `hex`, and `base64`. The default is `array`. + +`client[n].packet`: adds fixed data. Conflicts with `rand`. + +### header-dns + +```json +{ + "domain": "www.example.com" +} +``` + +### mkcp-aes128gcm + +```json +{ + "password": "your-password" +} +``` + +### noise + +```json +{ + "reset": 0, + "noise": [ + { + "rand": "1-8192", + "randRange": "0-255", + "type": "", + "packet": [], + "delay": "10-20" + } + ] +} +``` + +`noise[n].rand`: adds random bytes, or a specified random length of bytes. Conflicts with `packet`. + +`noise[n].randRange`: range of random-byte values. The default is `0-255`. + +`noise[n].type`: the type of `packet`. Supported values are `array`, `str`, `hex`, and `base64`. The default is `array`. + +`noise[n].packet`: adds fixed data. Conflicts with `rand`. + +`noise[n].delay`: delay in milliseconds. After sending one noise item, Xray waits for the specified time before sending the next one. + +### salamander + +```json +{ + "password": "your-password" +} +``` + +### sudoku + +```json +{ + "password": "", + "ascii": "", + + "customTable": "", + "customTables": [""], + + "paddingMin": 0, + "paddingMax": 0 +} +``` + +The same meanings as in the TCP version apply here. + +### xdns + +```json +{ + "domain": "www.example.com" +} +``` + +### xicmp + +```json +{ + "listenIp": "0.0.0.0", + "id": 0 +} +``` + +`listenIp`: the IP address to listen on. + +`id`: when multiple clients share the same IP, it is recommended that the server keep this value at `0`. + +> `quicParams`: [quicParamsObject](#quicParams) + +### quicParams + +```json +{ + "congestion": "force-brutal", + "debug": false, + "brutalUp": "60 mbps", + "brutalDown": 0, + "udpHop": { + "ports": "20000-50000", + "interval": "5-10" + }, + "initStreamReceiveWindow": 8388608, + "maxStreamReceiveWindow": 8388608, + "initConnectionReceiveWindow": 20971520, + "maxConnectionReceiveWindow": 20971520, + "maxIdleTimeout": 30, + "keepAlivePeriod": 0, + "disablePathMTUDiscovery": false, + "maxIncomingStreams": 1024 +} +``` + +Used for QUIC parameter tuning in XHTTP H3 and Hysteria. + +> `congestion`: reno | bbr | brutal | force-brutal + +Congestion-control algorithm. Hysteria defaults to `brutal`. XHTTP H3 defaults to `bbr`. + +`reno` and `bbr` are well-known algorithms. + +`brutal` negotiates a fixed packet-sending rate with the peer, or falls back to BBR. It is supported only by Hysteria, because XHTTP has no negotiation mechanism. + +`force-brutal` is the same as `brutal`, but it forcibly uses the fixed upstream rate from `brutalUp` and ignores peer negotiation. + +> `debug`: false | true + +Enable logging for the `bbr` and `brutal` congestion-control implementations. + +> `brutalUp`: string + +> `brutalDown`: string + +Upload and download rate limits. The default value is `0`. + +The format is user-friendly and supports common bit-rate forms such as `1000000`, `100kb`, `20 mb`, `100 mbps`, `1g`, and `1 tbps`. It is case-insensitive, spaces are optional, and when no unit is given the default is `bps`. The value must not be lower than 65535 bps. + +The negotiation behavior is the same as Hysteria Brutal: + +The server-side value limits the highest Brutal-mode rate the client is allowed to choose. `0` means the client is not limited by the server. + +When the client value is `0`, it uses BBR mode. When it is non-zero, it uses Brutal mode and is still constrained by the server-side limit. + +Remember the directions are relative: the server's upload is the client's download, and the server's download is the client's upload. + +> `udpHop`: {"ports": string, "interval": number} + +UDP port-hopping configuration. + +`ports` specifies the hopping range. It can be a single numeric string like `"1234"`, or a range like `"1145-1919"`, which means ports 1145 through 1919. Commas can be used to combine ranges, for example `11,13,15-17`. + +`interval` is the port-hopping interval in seconds. The minimum is 5. The default is 30 seconds. + +> `initStreamReceiveWindow`: number + +> `maxStreamReceiveWindow`: number + +> `initConnectionReceiveWindow`: number + +> `maxConnectionReceiveWindow`: number + +These four are low-level QUIC window parameters. **Do not change them unless you fully understand what you are doing.** If you do need to change them, it is recommended to keep the ratio between stream and connection receive windows at 2:5. + +> `maxIdleTimeout`: number + +Maximum idle timeout in seconds. This is how long the server waits without receiving any client data before closing the connection. The supported range is 4 to 120 seconds. The default is 30 seconds. + +> `keepAlivePeriod`: number + +QUIC KeepAlive interval in seconds. The supported range is 2 to 60 seconds. Disabled by default. + +> `disablePathMTUDiscovery`: bool + +Whether to disable path MTU discovery. + +Other implementations forcibly disable this on systems other than Linux, Windows, and Darwin, while Xray does not enforce that. If your operating system is outside those three, you may need to disable it manually. + +> `maxIncomingStreams`: number + +Server-side only. If set, it must not be smaller than `8`. diff --git a/docs/en/config/transports/httpupgrade.md b/docs/en/config/transports/httpupgrade.md index 2f72c212..7640749c 100644 --- a/docs/en/config/transports/httpupgrade.md +++ b/docs/en/config/transports/httpupgrade.md @@ -7,9 +7,9 @@ Its design is not recommended for standalone use; instead, it is intended to wor **It is recommended to switch to [XHTTP](https://github.com/XTLS/Xray-core/discussions/4113) to avoid significant traffic fingerprints such as HTTPUpgrade's "ALPN is http/1.1".** ::: -## HttpUpgradeObject +## HTTPUpgradeObject -`HttpUpgradeObject` corresponds to the `httpupgradeSettings` item in [`StreamSettingsObject`](../transport.md#streamsettingsobject). +`HTTPUpgradeObject` corresponds to the `httpupgradeSettings` item in [`StreamSettingsObject`](../transport.md#streamsettingsobject). ```json { diff --git a/docs/en/config/transports/index.md b/docs/en/config/transports/index.md index cac60324..0ef2b2b1 100644 --- a/docs/en/config/transports/index.md +++ b/docs/en/config/transports/index.md @@ -1,6 +1,8 @@ -# Xray Transport Layer +# Xray Transport Configuration -Xray supports the following transport layers: +Xray supports the following transport configuration categories: + +## Transport Methods - [RAW](raw.md) - [XHTTP: Beyond REALITY](xhttp.md) @@ -9,3 +11,13 @@ Xray supports the following transport layers: - [WebSocket](websocket.md) - [HTTPUpgrade](httpupgrade.md) - [Hysteria](hysteria.md) + +## Transport Security + +- [REALITY](reality.md) +- [TLS](tls.md) + +## Additional Configuration + +- [FinalMask](finalmask.md) +- [Sockopt](sockopt.md) diff --git a/docs/en/config/transports/mkcp.md b/docs/en/config/transports/mkcp.md index 373df430..dc6129f5 100644 --- a/docs/en/config/transports/mkcp.md +++ b/docs/en/config/transports/mkcp.md @@ -37,7 +37,7 @@ Please ensure that the firewall configuration on the host is correct. ``` ::: tip -The `header` and `seed` fields have been removed. Please use [FinalMask](../transport.md#finalmaskobject) for configuration. +The `header` and `seed` fields have been removed. Please use [FinalMask](./finalmask.md#finalmaskobject) for configuration. Additionally, the previously default mKCP obfuscation has also been removed. To connect to a legacy server, you need to configure `mkcp-original` in FinalMask. ::: diff --git a/docs/en/config/transports/reality.md b/docs/en/config/transports/reality.md new file mode 100644 index 00000000..6c598142 --- /dev/null +++ b/docs/en/config/transports/reality.md @@ -0,0 +1,203 @@ +# REALITY + +REALITY is a modified form of TLS that uses the appearance and handshake characteristics of a target site as camouflage. + +:::: tip +REALITY is currently one of the most secure transport-security schemes, and from the outside its traffic shape is consistent with ordinary web browsing.
+Enabling REALITY together with a suitable XTLS Vision flow-control mode can improve performance by several times or even more than ten times. + +::: details For developers +REALITY only modifies TLS. On the client side it mainly requires slight handling around a fully random session ID and custom certificate verification, and in theory it is broadly compatible with most TLS combinations. +For more information, see the [REALITY project](https://github.com/XTLS/REALITY). +::: +:::: + +## RealityObject + +`RealityObject` corresponds to the `realitySettings` item in [`StreamSettingsObject`](../transport.md#streamsettingsobject). + +```json +{ + // outbound example; also applies to inbound + "outbounds": [ + { + // ... + "streamSettings": { + "security": "reality", + "realitySettings": { + // [!code focus:28] + // Inbound (server-side) settings + "show": false, + "target": "example.com:443", + "xver": 0, + "serverNames": ["example.com", "www.example.com"], + "privateKey": "", + "minClientVer": "", + "maxClientVer": "", + "maxTimeDiff": 0, + "shortIds": ["", "0123456789abcdef"], + "mldsa65Seed": "", + "limitFallbackUpload": { + "afterBytes": 0, + "bytesPerSec": 0, + "burstBytesPerSec": 0 + }, + "limitFallbackDownload": { + "afterBytes": 0, + "bytesPerSec": 0, + "burstBytesPerSec": 0 + }, + // Outbound (client-side) settings + "serverName": "", + "fingerprint": "chrome", + "password": "", + "shortId": "", + "mldsa65Verify": "", + "spiderX": "" + } + } + } + ] +} +``` + +> `show`: true | false + +When set to `true`, debug information is printed. + +::: tip +The following fields are for **inbound** (**server-side**) configuration. +::: + +> `target`: string + +Required. The format is the same as VLESS fallback [dest](../features/fallback.md#fallbackobject). + +The old name was `dest`. In current versions the two fields are aliases. + +If `target` supports the post-quantum key-exchange algorithm X25519MLKEM768, the REALITY client also automatically uses that post-quantum algorithm for key negotiation. You can check support with `xray tls ping cloudflare.com`, replacing the domain with your `target` and optionally including a port. + +The core decides whether the current configuration is client-side or server-side based on whether this field exists. Do not fill it in on the client side, or it will cause incorrect detection. + +::: warning +For camouflage reasons, Xray **directly forwards** traffic that fails authentication, meaning traffic that is not a valid REALITY request, to `target`. +If the IP address of the `target` site is special, for example a site behind Cloudflare CDN, your server effectively becomes a port forwarder for Cloudflare and may be abused after scanning. + +To avoid that, consider placing Nginx or something similar in front to filter out unwanted SNI values. +You can also consider configuring `limitFallbackUpload` and `limitFallbackDownload` to limit the rate. +::: + +> `xver`: number + +Optional. The format is the same as VLESS fallback [xver](../features/fallback.md#fallbackobject). + +> `serverNames`: [string] + +Required. The list of `serverName` values allowed for clients. `*` wildcards are not supported. + +Usually this should stay consistent with `target`. In practice, valid values are any SNI accepted by the server according to the behavior of `target`, and typically refer to the [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) values on the returned certificate. + +The list may contain an empty string `""`, meaning connections without SNI are accepted. Using this feature does not require `target` to have an IP certificate; you only need to ensure that it does not reject a Client Hello without SNI. When using this feature, the client-side `serverName` cannot be empty and should instead be filled with any valid IP address as a placeholder. + +You can use `xray tls ping` to observe how the server responds to requests without SNI. + +> `privateKey`: string + +Required. Generate it with `./xray x25519`. + +> `minClientVer`: string + +Optional. Minimum Xray client version, in `x.y.z` format. + +> `maxClientVer`: string + +Optional. Maximum Xray client version, in `x.y.z` format. + +> `maxTimeDiff`: number + +Optional. Maximum allowed time difference, in milliseconds. + +> `shortIds`: [string] + +Required. The list of available `shortId` values for clients, which can be used to distinguish different clients. + +See the `shortId` field for the required format. + +If the list contains an empty string, the client-side `shortId` may also be empty. + +> `mldsa65Seed`: string + +Server-only. The private key used to add an extra post-quantum signature to the certificate sent to the REALITY client, using ML-DSA-65. If a quantum computer capable of breaking x25519 ever exists, leaked `password` material could allow MITM attacks; this feature is intended to prevent that future risk. + +Generate the keypair with `xray mldsa65`. After the server is configured with the private key, the signature is added only as a certificate extension, so it does not affect old clients or clients that do not enable this feature. + +Note that after enabling this feature, the certificate returned by `target` **must** be longer than 3500 bytes, because the post-quantum signature makes the temporary REALITY certificate larger. To avoid becoming a fingerprint, the `target` certificate also needs to be large. You can inspect this with `xray tls ping example.com`. For fully post-quantum security, `target` also needs to support the X25519MLKEM768 post-quantum key exchange, which can be checked with the same command. + +> `limitFallbackUpload` / `limitFallbackDownload` + +::: warning +The best practice for REALITY is still to borrow certificates from the same ASN, so in most cases you do not need this feature. It is only worth considering when you are forced to borrow certificates from something like a free CDN such as Cloudflare and want to avoid your server becoming an acceleration node for others. + +Fallback rate limiting is itself a fingerprint and is not recommended. If you are developing a panel or one-click script, make sure these parameters are randomized. +::: + +::: tip +`limitFallbackUpload` and `limitFallbackDownload` are optional and can rate-limit fallback connections that fail verification. `bytesPerSec` defaults to `0`, which means disabled. + +Mechanism: for each unverified fallback connection, the rate-limiting algorithm starts after `afterBytes` bytes have been transmitted. +The algorithm uses a token bucket. The bucket capacity is `burstBytesPerSec`. Each transmitted byte consumes one token. The bucket starts full with `burstBytesPerSec` tokens. +Every second the bucket is refilled with `bytesPerSec` tokens until full. + +Example: `afterBytes=10485760`, `burstBytesPerSec=5242880`, `bytesPerSec=1048576` means traffic is limited to 1 MB/s after 15 MB has been transmitted. If transmission pauses, it can burst back up to 5 MB/s after 5 seconds and then settle again at 1 MB/s. + +Guidance: if `afterBytes` and `burstBytesPerSec` are too large, rate limiting has little practical effect. If `bytesPerSec` and `burstBytesPerSec` are too small, the behavior becomes easy to detect. +These parameters should be chosen with the resource size of the borrowed site in mind. If you do not want bursts, set `burstBytesPerSec` to `0`. +::: + +> `afterBytes`: number + +Optional. Starts rate limiting fallback REALITY connections only after the specified number of bytes has been transmitted. The default is `0`. + +> `bytesPerSec`: number + +Optional. Base rate limit for fallback REALITY connections, in bytes per second. The default is `0`, meaning disabled. + +> `burstBytesPerSec`: number + +Optional. Burst rate limit for fallback REALITY connections, in bytes per second. It takes effect when it is greater than `bytesPerSec`. + +::: tip +The following fields are for **outbound** (**client-side**) configuration. +::: + +> `serverName`: string + +One of the server-side `serverNames`. + +The client can also set this to any IP address. In that case Xray sends a Client Hello without an SNI extension. To use this feature, the server-side `serverNames` must contain an empty string `""`. + +> `fingerprint`: string + +Required. Same as [TLSObject](./tls.md#tlsobject). Note that `unsafe`, which disables uTLS for TLS, is not supported here because REALITY relies on that library to manipulate lower-level TLS parameters. + +> `shortId`: string + +One of the server-side `shortIds`. + +Its length is 8 bytes, which means up to 16 hexadecimal characters in the range `0` to `f`. It may be shorter than 16 characters, and the core pads trailing zeroes automatically, but the number of characters must be **even**, because one byte is represented by two hex digits. + +For example, `aa1234` is automatically expanded to `aa12340000000000`, but `aaa1234` causes an error. + +Zero is also even, so if the server-side `shortIds` contains an empty string `""`, the client-side value may also be empty. + +> `password`: string + +Required. The public key corresponding to the server private key. Generate it with `./xray x25519 -i "server private key"`. The old field name was `publicKey`, but it was renamed to avoid misunderstanding. It is indeed an x25519 public key, but in the REALITY design it is held by the client and should not be treated as something to publish openly. + +> `mldsa65Verify` + +Optional. The public key used for `mldsa65` signature verification. When non-empty, Xray uses it to verify the certificate returned by the server. See the description of `mldsa65Seed` for details. + +> `spiderX`: string + +Initial crawler path and parameters. It is recommended that each client use a different value. diff --git a/docs/en/config/transports/sockopt.md b/docs/en/config/transports/sockopt.md new file mode 100644 index 00000000..c10a769d --- /dev/null +++ b/docs/en/config/transports/sockopt.md @@ -0,0 +1,298 @@ +# Sockopt + +Sockopt is used to configure low-level network behavior. + +It can be used to tune transparent proxying, DNS resolution strategy, and many other socket-level options. + +## SockoptObject + +`SockoptObject` corresponds to the `sockopt` item in [`StreamSettingsObject`](../transport.md#streamsettingsobject). + +```json +{ + // outbound example; also applies to inbound + "outbounds": [ + { + // ... + "streamSettings": { + "sockopt": { + // [!code focus:18] + "mark": 0, + "tcpMaxSeg": 1440, + "tcpFastOpen": false, + "tproxy": "off", + "domainStrategy": "AsIs", + "happyEyeballs": {}, + "dialerProxy": "", + "acceptProxyProtocol": false, + "tcpKeepAliveInterval": 0, + "tcpKeepAliveIdle": 300, + "tcpUserTimeout": 10000, + "tcpcongestion": "bbr", + "interface": "wg0", + "V6Only": false, + "tcpWindowClamp": 600, + "tcpMptcp": false, + "addressPortStrategy": "", + "customSockopt": [] + } + } + } + ] +} +``` + +> `mark`: number + +An integer. When non-zero, outbound connections are marked with this value through `SO_MARK`. + +- Linux only. +- Requires `CAP_NET_ADMIN`. + +> `tcpMaxSeg`: number + +Used to set the maximum segment size of TCP packets. + +> `tcpFastOpen`: true | false | number + +Whether to enable [TCP Fast Open](https://en.wikipedia.org/wiki/TCP_Fast_Open). + +When set to `true` or a positive integer, TFO is enabled. When set to `false` or a negative value, TFO is forcibly disabled. When the field is absent or `0`, the system default is used. This option is available for both inbound and outbound. + +- It is only available on the following operating systems or later: + - Linux 3.16: requires the kernel parameter `net.ipv4.tcp_fastopen`. This parameter is a bitmap where `0x1` allows the client side and `0x2` allows the server side. The default is `0x1`. If the server must enable TFO, set it to `0x3`. + - ~~Windows 10 (1607)~~, but the implementation is incorrect + - Mac OS 10.11 / iOS 9, needs testing + - FreeBSD 10.3 on server side / 12.0 on client side: requires `net.inet.tcp.fastopen.server_enabled=1` and `net.inet.tcp.fastopen.client_enabled=1`, needs testing + +- For inbound, a positive integer here means the [maximum number of pending TFO connection requests](https://tools.ietf.org/html/rfc7413#section-5.1). **Not every operating system supports setting this here**: + - Linux / FreeBSD: the positive integer is used as the limit. The maximum accepted value is 2147483647. If set to `true`, the value becomes `256`. On Linux, `net.core.somaxconn` also caps it, so if you exceed `somaxconn`, raise that as well. + - Mac OS: `true` or a positive integer only means enabling TFO. The backlog must be configured separately via `net.inet.tcp.fastopen_backlog`. + - Windows: `true` or a positive integer only means enabling TFO. + +- For outbound, `true` or a positive integer simply means enabling TFO on any supported OS. + +> `tproxy`: "redirect" | "tproxy" | "off" + +Whether to enable transparent proxying. Linux only. + +- `"redirect"`: transparent proxy in Redirect mode, supporting all IPv4 and IPv6 TCP connections +- `"tproxy"`: transparent proxy in TProxy mode, supporting all IPv4 and IPv6 TCP and UDP connections +- `"off"`: disable transparent proxying + +Transparent proxying requires root or `CAP_NET_ADMIN`. + +::: danger +When [Dokodemo-door](../inbounds/tunnel.md) has `followRedirect` set to `true`, and `tproxy` is empty in Sockopt, the `tproxy` value is set to `"redirect"`. +::: + +> `domainStrategy`: "AsIs"
+> "UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
+> "ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4" + +The default value is `"AsIs"`. + +When the target address is a domain name, this field controls how outbound connections resolve and use that target: + +- With `"AsIs"`, Xray does not specially handle the domain name. In the end it uses Go's built-in dialer directly. The priority is fixed to the RFC 6724 default and does not follow configurations such as `gai.conf`, so in practice IPv6 is usually preferred. +- With any other value, Xray uses the Xray-core [built-in DNS server](../dns.md) for resolution. If there is no `DNSObject`, system DNS is used. If multiple IP addresses match, the core randomly picks one target IP. +- `"IPv4"` means try IPv4 only. `"IPv4v6"` means try IPv4 or IPv6, but for dual-stack domains prefer IPv4. The same logic applies to the IPv6-first variants. +- When built-in DNS also sets `"queryStrategy"`, the actual behavior is the intersection of the two settings. Only IP types included in both are resolved. For example, `"queryStrategy": "UseIPv4"` together with `"domainStrategy": "UseIP"` behaves the same as `"domainStrategy": "UseIPv4"`. +- When using a `"Use"` option, Xray falls back to `"AsIs"` if the resolution result does not match the requested family, such as a domain that only has IPv4 while using `UseIPv6`. +- When using a `"Force"` option, the connection fails outright if the resolution result does not match the requested family. + +::: tip TIP +When using `"UseIP"` or `"ForceIP"`, and [OutboundObject](../outbound.md#outboundobject) specifies `sendThrough`, the core automatically infers whether IPv4 or IPv6 is needed from the local address. If you manually force a single IP family, such as `UseIPv4`, but it conflicts with `sendThrough`, the connection fails. +::: + +::: danger +Improper use of this feature can create an infinite loop. + +Short version: connecting to the server needs a DNS result, but completing the DNS query also needs to connect to the server. + +> Tony: which came first, the chicken or the egg? + +Detailed explanation: + +1. Trigger condition: the proxy server is `proxy.com`, and the built-in DNS server is enabled in non-Local mode. +2. Before Xray establishes a TCP connection to `proxy.com`, it queries `proxy.com` through the built-in DNS server. +3. The built-in DNS server connects to `dns.com` and sends a query to obtain the IP of `proxy.com`. +4. Bad routing rules cause the request sent in step 3 to be proxied through `proxy.com`. +5. Xray now tries to establish another TCP connection to `proxy.com`. +6. Before doing that, it again queries `proxy.com` through the built-in DNS server. +7. The built-in DNS server reuses the connection from step 3 and sends the new query. +8. The problem appears: the connection from step 3 is waiting for the query result from step 7, while step 7 cannot finish until the connection from step 3 is fully established. +9. Good game. + +Possible solutions: + +- Fix the traffic split of the built-in DNS server. +- Use hosts. +- ~~If you still do not know how to solve it, do not use this feature.~~ + +So this feature is **not recommended** for inexperienced users unless they understand the routing implications. +::: + +> `dialerProxy`: "" + +An outbound identifier. When non-empty, the specified outbound is used to establish the connection. It can be used for chained forwarding that still respects transport configuration. + +::: danger +This option is incompatible with `ProxySettingsObject.Tag`. +::: + +> `acceptProxyProtocol`: true | false + +Inbound-only. Controls whether PROXY protocol is accepted. + +[PROXY protocol](https://www.haproxy.org/download/2.2/doc/proxy-protocol.txt) is used to pass the real source IP and port. If you do not know what it is, ignore this option. + +Common reverse proxies such as HAProxy and Nginx can be configured to send it, and VLESS fallback `xver` can also send it. + +When set to `true`, the peer must send PROXY protocol v1 or v2 immediately after the underlying TCP connection is established, otherwise the connection is closed. + +> `tcpKeepAliveIdle`: number + +TCP idle threshold in seconds. Once a TCP connection has been idle for this long, Keep-Alive probes begin. + +For outbound, Xray uses Chrome's default values, where both idle and interval are 45 seconds. Setting either this field or `tcpKeepAliveInterval` to a negative value disables that default keepalive; a positive value overrides it. + +For inbound, Keep-Alive is disabled by default. It becomes enabled when either this field or `tcpKeepAliveInterval` is non-zero. If only one is set, the other follows the operating-system default. + +> `tcpKeepAliveInterval`: number + +Time interval in seconds between Keep-Alive probes after TCP enters Keep-Alive state. The rest of the behavior is described above. + +> `tcpUserTimeout`: number + +In milliseconds. See: https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md + +> `tcpcongestion`: "" + +TCP congestion-control algorithm. Linux only. +When unset, the operating-system default is used. + +::: tip Common algorithms + +- `bbr` (recommended) +- `cubic` +- `reno` + +::: + +::: tip +Run `sysctl net.ipv4.tcp_congestion_control` to see the current system default. +::: + +> `interface`: "" + +Bind the outbound connection to a specific network-interface name. Supported on Linux, iOS, Mac OS, and Windows. + +> `V6Only`: true | false + +When set to `true`, listening on `::` accepts only IPv6 connections. Linux only. + +> `tcpWindowClamp`: number + +Bind the advertised TCP window size to this value. The kernel chooses the larger value between this and `SOCK_MIN_RCVBUF / 2`. + +> `tcpMptcp`: true | false + +The default value is `false`. When set to `true`, [Multipath TCP](https://en.wikipedia.org/wiki/Multipath_TCP) is enabled. This is client-only, because starting with Go 1.24 MPTCP is enabled by default when listening. It currently requires Linux kernel 5.6 or later. + +> `tcpNoDelay`: true | false + +This field has been removed because Go enables TCP no delay by default. If you want to disable it, do so through `customSockopt`. + +> `addressPortStrategy`: "none" | "SrvPortOnly" | "SrvAddressOnly" | "SrvPortAndAddress" | "TxtPortOnly" | "TxtAddressOnly" | "TxtPortAndAddress" + +Use SRV records or TXT records to specify the target address and or port used by outbound. The default value is `none`, which disables the feature. + +These lookups go through system DNS rather than Xray's built-in DNS. The queried name is the outbound domain name. If the lookup fails, the request is sent using the original address and port. + +`Srv*` means querying SRV records in their standard format. `Txt*` means querying TXT records in a format such as `127.0.0.1:80`. + +`PortOnly` resets only the port. `AddressOnly` resets only the address. `PortAndAddress` resets both. + +This option takes effect before `domainStrategy` inside `sockopt`. After the address is rewritten, it is still resolved according to `domainStrategy`, if any. However, it takes effect after `Freedom`'s own `domainStrategy`, so if that one already resolved the domain to an IP, this option no longer works. + +As a practical consequence, if ordinary domain traffic is sent into a `Freedom` outbound with `AsIs`, enabling this field makes the core try to resolve and rewrite the address and port, for example by querying `google.com` for SRV records. + +> `customSockopt`: [] + +An array for advanced users to specify any needed socket option. In theory, all connection-related settings above can be expressed here, and you can also set other socket options that exist but are not exposed directly by the core. It currently supports Linux, Windows, and Darwin. The example below is equivalent to `"tcpcongestion": "bbr"`. + +Make sure you understand socket programming before using it. + +```json +"customSockopt": [ + { + "system": "linux", + "type": "str", + "level": "6", + "opt": "13", + "value": "bbr" + } +] +``` + +> `system`: "" + +Optional. Restricts the option to a specific operating system. If the current system does not match, the option is skipped. Supported values are `linux`, `windows`, and `darwin`, all in lowercase. If left empty, the option is applied directly. + +> `type`: "" + +Required. The value type to set. Currently `int` and `str` are supported. + +> `level`: "" + +Optional. Protocol level. The default is `6`, which means TCP. + +> `opt`: "" + +The option number to operate on, in decimal. In the example above, `13` is the decimal form of `TCP_CONGESTION`, whose hexadecimal value is `0xd`. + +> `value`: "" + +The value to set. In the example above, the value is `bbr`. + +When `type` is `int`, the value must be a decimal number. + +> `happyEyeballs`: [HappyEyeballsObject](#happyeyeballsobject) + +An RFC 8305 Happy Eyeballs implementation, TCP only. When the target is a domain name, it races the resolved addresses and chooses the first successful one. It only works when `Sockopt.domainStrategy` is not `AsIs`. + +Note that `UseIPv4v6` and `ForceIPv4v6` effectively reduce the usable list to IPv4 and only query IPv6 if IPv4 resolution fails. That is not recommended. Prefer `UseIP` or `ForceIP` together with `HappyEyeballs.interleave`. + +::: warning +Do not use this together with the `domainStrategy` on a `Freedom` outbound, because then `Sockopt` only sees the final IP after replacement. +::: + +### HappyEyeballsObject + +```json +"happyEyeballs": { + "tryDelayMs": 250, + "prioritizeIPv6": false, + "interleave": 1, + "maxConcurrentTry": 4 +} +``` + +> `tryDelayMs`: number + +Delay between each racing attempt, in milliseconds. The default is `0`, which disables the feature. A recommended value is `250`. + +> `prioritizeIPv6`: bool + +Controls which IP family comes first after sorting. The default is `false`, meaning IPv4 comes first. + +> `interleave`: number + +The RFC 8305 `First Address Family Count`. The default value is `1`. It controls how IPv4 and IPv6 addresses are interleaved. + +For example, the waiting dial queue may be ordered as `46464646` when this is `1`, or `44664466` when it is `2`, where `6` means an IPv6 address and `4` means an IPv4 address. + +> `maxConcurrentTry`: number + +Maximum number of concurrent attempts. This prevents the core from launching too many connections when a domain resolves to many addresses and all of them fail. The default is `4`. Setting it to `0` disables Happy Eyeballs. diff --git a/docs/en/config/transports/tls.md b/docs/en/config/transports/tls.md new file mode 100644 index 00000000..f0723dd5 --- /dev/null +++ b/docs/en/config/transports/tls.md @@ -0,0 +1,338 @@ +# TLS + +TLS is a common transport-security mechanism. + +It can be used to configure transport-layer encryption, certificate verification, client fingerprints, and related certificate settings. + +## TLSObject + +`TLSObject` corresponds to the `tlsSettings` item in [`StreamSettingsObject`](../transport.md#streamsettingsobject). + +```json +{ + // outbound example; also applies to inbound + "outbounds": [ + { + // ... + "streamSettings": { + "security": "tls", + "tlsSettings": { + // [!code focus:18] + "serverName": "xray.com", + "verifyPeerCertByName": "", + "rejectUnknownSni": false, + "allowInsecure": false, + "alpn": ["h2", "http/1.1"], + "minVersion": "1.2", + "maxVersion": "1.3", + "cipherSuites": "Enter the cipher suite names you need here, separated by :", + "certificates": [], + "disableSystemRoot": false, + "enableSessionResumption": false, + "fingerprint": "", + "pinnedPeerCertSha256": "", + "curvePreferences": [""], + "masterKeyLog": "", + "echServerKeys": "", + "echConfigList": "", + "echSockopt": {} + } + } + } + ] +} +``` + +> `serverName`: string + +Server name. The server certificate's SAN must contain this value. It can be a domain name or an IP address. If it is a domain name, it will be sent in the SNI extension of the Client Hello. IP addresses will not send the SNI extension, because SNI does not allow IP addresses. If you fill in an IPv6 address, wrap it in `[]`. + +When left empty, the value in `address` is used automatically if that value is a domain name. + +Special value `"FromMitM"` causes Xray to use the SNI extracted from TLS decrypted by a `dokodemo-door` inbound. + +> `verifyPeerCertByName`: string + +Client-only. The SNI used for certificate verification. Multiple domain names can be separated with `,`; it is enough for any one SAN in the certificate to match one of them. This overrides the `serverName` used for verification and is intended for special cases such as domain fronting. + +Special value `"FromMitM"` causes Xray to additionally include the SNI extracted from TLS decrypted by a `dokodemo-door` inbound. + +> `rejectUnknownSni`: bool + +When set to `true`, the server rejects the TLS handshake if the received SNI does not match the certificate domain. The default is `false`. + +> `alpn`: [string] + +An array of strings that specifies the ALPN values used during TLS handshake. The default value is `["h2", "http/1.1"]`. + +Special value `["FromMitM"]`, when it is the only element, causes outbound TLS to reuse the ALPN from the TLS connection decrypted by a `dokodemo-door` inbound. + +> `minVersion`: string + +`minVersion` is the minimum acceptable TLS version. + +> `maxVersion`: string + +`maxVersion` is the maximum acceptable TLS version. + +> `cipherSuites`: string + +`cipherSuites` configures the list of supported cipher suites, separated by `:`. + +You can find Go cipher-suite names and descriptions [here](https://golang.org/src/crypto/tls/cipher_suites.go#L500) or [here](https://golang.org/src/crypto/tls/cipher_suites.go#L44). + +::: danger +These two options are not required in normal cases and usually do not affect security. If left unset, Go chooses automatically according to the platform. If you are not familiar with them, do not configure them. +::: + +> `allowInsecure`: true | false + +Whether to allow insecure connections. Client-only. The default value is `false`. + +When set to `true`, Xray does not verify the validity of the TLS certificate provided by the remote host. + +::: danger +~~For security reasons, this option should not be set to `true` in real deployments, otherwise you may be vulnerable to man-in-the-middle attacks.~~ + +This option is deprecated. Use `pinnedPeerCertSha256` to specify the certificate manually instead. +::: + +> `disableSystemRoot`: true | false + +Whether to disable the operating system's built-in CA certificates. The default value is `false`. + +When set to `true`, Xray uses only the certificates specified in `certificates` during TLS handshake. When set to `false`, Xray uses only the operating system's built-in CA certificates during TLS handshake. + +> `enableSessionResumption`: true | false + +Whether to enable session resumption. It is disabled by default, and session resumption is only attempted when both the server and the client enable it. + +If negotiation succeeds, certificates do not need to be transmitted during the handshake. This saves a tiny amount of handshake time, which is usually negligible. + +Note that this is not TLS 0-RTT. `gotls` does not support that feature yet, so this does not reduce TLS handshake RTT. + +> `fingerprint`: string + +This parameter configures the fingerprint of the `TLS Client Hello`. The default value is `chrome`. To revert to native Go TLS, set it to `unsafe`. When enabled, Xray uses the uTLS library to **simulate** a TLS fingerprint, or generates one randomly. Three configuration styles are supported: + +1. TLS fingerprints of the latest versions of common browsers, including: + +- `"chrome"` +- `"firefox"` +- `"safari"` +- `"ios"` +- `"android"` +- `"edge"` +- `"360"` +- `"qq"` + +2. Automatically generate a fingerprint when Xray starts: + +- `"random"`: randomly choose one from newer browser versions +- `"randomized"`: generate a completely random unique fingerprint that fully supports TLS 1.3 with X25519 + +3. Use native uTLS hello names such as `"HelloRandomizedNoALPN"` or `"HelloChrome_106_Shuffle"`. See the full list in the [uTLS library](https://github.com/refraction-networking/utls/blob/master/u_common.go#L434). + +::: tip +This feature only **simulates** the `TLS Client Hello` fingerprint. Behavior and other fingerprints remain the same as Go. If you want more complete browser-like TLS fingerprints and behavior, use [Browser Dialer](./websocket.md#browser-dialer). +::: + +::: tip +When this feature is enabled, some TLS options that affect TLS fingerprints are overridden by the uTLS library and stop taking effect, such as ALPN. +The parameters still passed through are: +`"serverName" "disableSystemRoot" "pinnedPeerCertSha256" "masterKeyLog"` +::: + +> `pinnedPeerCertSha256`: string + +Used to specify the SHA-256 hash of the remote server certificate. It uses hexadecimal encoding and is case-insensitive, for example `e8e2d387fdbffeb38e9c9065cf30a97ee23c0e3d32ee6f78ffae40966befccc9`. Multiple hash values can be joined with `,`, and verification succeeds if any one of them matches. + +This encoding matches the SHA-256 certificate fingerprint shown by the Chrome certificate viewer and the SHA-256 certificate fingerprint format used on crt.sh. You can compute it with `xray tls hash --cert `, or with `openssl x509 -noout -fingerprint -sha256 -in cert.pem`, including its colon-separated format. `xray tls ping` also prints the SHA-256 hash of the remote certificate. + +This check overrides normal certificate validation. There are two cases: + +- If the core finds that the matching hash belongs to a leaf certificate, verification succeeds immediately. +- If the core finds that the matching hash belongs to a CA certificate, whether root or intermediate, it uses the value in `serverName` to verify that the leaf certificate is signed by that CA. + +> `certificates`: \[ [CertificateObject](#certificateobject) \] + +Certificate list. Each item represents one certificate. A full chain is recommended. + +::: tip +If you want an A or A+ rating from tools such as ssllibs or myssl, see [this discussion](https://github.com/XTLS/Xray-core/discussions/56#discussioncomment-215600). +::: + +> `curvePreferences`: [string] + +An array of strings that specifies the curves supported when performing ECDHE during TLS handshake. Supported values are: + +```text +CurveP256 +CurveP384 +CurveP521 +X25519 +X25519MLKEM768 +SecP256r1MLKEM768* +SecP384r1MLKEM1024* +``` + +\*: not supported by uTLS + +As of Go 1.26, the default includes all curves above. Changing the order does not force either side to prefer a specific curve; the actual curve is negotiated by the key-exchange mechanism itself. + +> `masterKeyLog`: string + +Path to a `(Pre)-Master-Secret` log file. It can be used by software such as Wireshark to decrypt TLS connections sent by Xray. + +> `echServerKeys`: string + +Server-only parameter used to enable Encrypted Client Hello on the server. + +Use `xray tls ech --serverName example.com` to generate an ECH Server Key and its corresponding Config. `example.com` is the SNI exposed to the outside when SNI is encrypted, and can be any value. The Server Key includes the ECHConfig. If you lose the client-side Config, you can recover it with `xray tls ech -i "your server key"`. You can publish it in a DNS HTTPS record; see the format [here](https://dns.google/query?name=encryptedsni.com&rr_type=HTTPS) or in RFC 9460. + +Note that after ECH is configured, the server still accepts normal non-ECH connections. + +> `echConfigList`: string + +Client-only parameter that configures ECHConfig. A non-empty value means the client enables Encrypted Client Hello. Two formats are supported. + +The first is a fixed ECHConfig string, for example: + +`"AF7+DQBaAAAgACA51i3Ssu4wUMV4FNCc8iRX5J+YC4Bhigz9sacl2lCfSQAkAAEAAQABAAIAAQADAAIAAQACAAIAAgADAAMAAQADAAIAAwADAAtleGFtcGxlLmNvbQAA"` + +The second is querying a DNS server. For example, when using a CDN, you can dynamically obtain ECHConfig from HTTPS records. If a valid ECH Config is obtained, Xray obeys the TTL returned by the server. The query target is the configured SNI, or the configured server domain name if SNI is empty and the target is a domain name. + +The basic format is `"udp://1.1.1.1"`, meaning query ECHConfig through UDP DNS 1.1.1.1. You can also use `"https://1.1.1.1/dns-query"` or `h2c://` to query via DoH or h2c. All of these support an explicit port, such as `udp://1.1.1.1:53`. If omitted, the default port is 53 or 443 according to the protocol. + +You can also specify a dedicated domain for the ECHConfig lookup in the form `"example.com+https://1.1.1.1/dns-query"`. In that case Xray forcibly uses the ECHConfig from the DNS records of `example.com` for the connection. This is useful if you want to obtain ECHConfig from DNS without exposing that you are querying the target domain's HTTPS record, or when you do not want to publish HTTPS records under that domain. + +> `echSockopt`: [SockoptObject](./sockopt.md#sockoptobject) + +Adjusts the underlying socket options of the connection used when querying DNS for ECH records. + +### CertificateObject + +```json +{ + "ocspStapling": 0, + "oneTimeLoading": false, + "usage": "encipherment", + "buildChain": false, + "certificateFile": "/path/to/certificate.crt", + "keyFile": "/path/to/key.key", + "certificate": [ + "--BEGIN CERTIFICATE--", + "MIICwDCCAaigAwIBAgIRAO16JMdESAuHidFYJAR/7kAwDQYJKoZIhvcNAQELBQAw", + "ADAeFw0xODA0MTAxMzU1MTdaFw0xODA0MTAxNTU1MTdaMAAwggEiMA0GCSqGSIb3", + "DQEBAQUAA4IBDwAwggEKAoIBAQCs2PX0fFSCjOemmdm9UbOvcLctF94Ox4BpSfJ+", + "3lJHwZbvnOFuo56WhQJWrclKoImp/c9veL1J4Bbtam3sW3APkZVEK9UxRQ57HQuw", + "OzhV0FD20/0YELou85TwnkTw5l9GVCXT02NG+pGlYsFrxesUHpojdl8tIcn113M5", + "pypgDPVmPeeORRf7nseMC6GhvXYM4txJPyenohwegl8DZ6OE5FkSVR5wFQtAhbON", + "OAkIVVmw002K2J6pitPuJGOka9PxcCVWhko/W+JCGapcC7O74palwBUuXE1iH+Jp", + "noPjGp4qE2ognW3WH/sgQ+rvo20eXb9Um1steaYY8xlxgBsXAgMBAAGjNTAzMA4G", + "A1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA", + "MA0GCSqGSIb3DQEBCwUAA4IBAQBUd9sGKYemzwPnxtw/vzkV8Q32NILEMlPVqeJU", + "7UxVgIODBV6A1b3tOUoktuhmgSSaQxjhYbFAVTD+LUglMUCxNbj56luBRlLLQWo+", + "9BUhC/ow393tLmqKcB59qNcwbZER6XT5POYwcaKM75QVqhCJVHJNb1zSEE7Co7iO", + "6wIan3lFyjBfYlBEz5vyRWQNIwKfdh5cK1yAu13xGENwmtlSTHiwbjBLXfk+0A/8", + "r/2s+sCYUkGZHhj8xY7bJ1zg0FRalP5LrqY+r6BckT1QPDIQKYy615j1LpOtwZe/", + "d4q7MD/dkzRDsch7t2cIjM/PYeMuzh87admSyL6hdtK0Nm/Q", + "--END CERTIFICATE--" + ], + "key": [ + "--BEGIN RSA PRIVATE KEY--", + "MIIEowIBAAKCAQEArNj19HxUgoznppnZvVGzr3C3LRfeDseAaUnyft5SR8GW75zh", + "bqOeloUCVq3JSqCJqf3Pb3i9SeAW7Wpt7FtwD5GVRCvVMUUOex0LsDs4VdBQ9tP9", + "GBC6LvOU8J5E8OZfRlQl09NjRvqRpWLBa8XrFB6aI3ZfLSHJ9ddzOacqYAz1Zj3n", + "jkUX+57HjAuhob12DOLcST8np6IcHoJfA2ejhORZElUecBULQIWzjTgJCFVZsNNN", + "itieqYrT7iRjpGvT8XAlVoZKP1viQhmqXAuzu+KWpcAVLlxNYh/iaZ6D4xqeKhNq", + "IJ1t1h/7IEPq76NtHl2/VJtbLXmmGPMZcYAbFwIDAQABAoIBAFCgG4phfGIxK9Uw", + "qrp+o9xQLYGhQnmOYb27OpwnRCYojSlT+mvLcqwvevnHsr9WxyA+PkZ3AYS2PLue", + "C4xW0pzQgdn8wENtPOX8lHkuBocw1rNsCwDwvIguIuliSjI8o3CAy+xVDFgNhWap", + "/CMzfQYziB7GlnrM6hH838iiy0dlv4I/HKk+3/YlSYQEvnFokTf7HxbDDmznkJTM", + "aPKZ5qbnV+4AcQfcLYJ8QE0ViJ8dVZ7RLwIf7+SG0b0bqloti4+oQXqGtiESUwEW", + "/Wzi7oyCbFJoPsFWp1P5+wD7jAGpAd9lPIwPahdr1wl6VwIx9W0XYjoZn71AEaw4", + "bK4xUXECgYEA3g2o9WqyrhYSax3pGEdvV2qN0VQhw7Xe+jyy98CELOO2DNbB9QNJ", + "8cSSU/PjkxQlgbOJc8DEprdMldN5xI/srlsbQWCj72wXxXnVnh991bI2clwt7oYi", + "pcGZwzCrJyFL+QaZmYzLxkxYl1tCiiuqLm+EkjxCWKTX/kKEFb6rtnMCgYEAx0WR", + "L8Uue3lXxhXRdBS5QRTBNklkSxtU+2yyXRpvFa7Qam+GghJs5RKfJ9lTvjfM/PxG", + "3vhuBliWQOKQbm1ZGLbgGBM505EOP7DikUmH/kzKxIeRo4l64mioKdDwK/4CZtS7", + "az0Lq3eS6bq11qL4mEdE6Gn/Y+sqB83GHZYju80CgYABFm4KbbBcW+1RKv9WSBtK", + "gVIagV/89moWLa/uuLmtApyEqZSfn5mAHqdc0+f8c2/Pl9KHh50u99zfKv8AsHfH", + "TtjuVAvZg10GcZdTQ/I41ruficYL0gpfZ3haVWWxNl+J47di4iapXPxeGWtVA+u8", + "eH1cvgDRMFWCgE7nUFzE8wKBgGndUomfZtdgGrp4ouLZk6W4ogD2MpsYNSixkXyW", + "64cIbV7uSvZVVZbJMtaXxb6bpIKOgBQ6xTEH5SMpenPAEgJoPVts816rhHdfwK5Q", + "8zetklegckYAZtFbqmM0xjOI6bu5rqwFLWr1xo33jF0wDYPQ8RHMJkruB1FIB8V2", + "GxvNAoGBAM4g2z8NTPMqX+8IBGkGgqmcYuRQxd3cs7LOSEjF9hPy1it2ZFe/yUKq", + "ePa2E8osffK5LBkFzhyQb0WrGC9ijM9E6rv10gyuNjlwXdFJcdqVamxwPUBtxRJR", + "cYTY2HRkJXDdtT0Bkc3josE6UUDvwMpO0CfAETQPto1tjNEDhQhT", + "--END RSA PRIVATE KEY--" + ] +} +``` + +Server certificates are hot-reloaded every 3600 seconds, which is once per hour. + +> `ocspStapling`: number + +OCSP stapling refresh interval in seconds. The default value is `0`. Any non-zero value enables OCSP stapling and also replaces the default 3600-second certificate hot-reload interval; reloading and OCSP stapling happen together. + +> `oneTimeLoading`: true | false + +Load only once. The default is `false`. When set to `true`, both certificate hot reload and OCSP stapling are disabled. + +> `usage`: "encipherment" | "verify" | "issue" + +Certificate usage. The default value is `"encipherment"`. + +- `"encipherment"`: the certificate is used for TLS authentication and encryption +- `"verify"`: the certificate is used to verify remote TLS certificates; in this case it must be a CA certificate +- `"issue"`: the certificate is used to issue other certificates; in this case it must also be a CA certificate + +::: tip TIP 1 +On Windows, you can install a self-signed CA certificate into the system store to verify remote TLS certificates. +::: + +::: tip TIP 2 +When a new client request arrives, suppose the specified `serverName` is `"xray.com"`. Xray first looks through the certificate list for a certificate usable for `"xray.com"`. If none is found, it uses any certificate whose `usage` is `"issue"` to issue one suitable for `"xray.com"` with a one-hour validity period, then adds that new certificate to the list for later use. +::: + +::: tip TIP 3 +When both `certificateFile` and `certificate` are specified, Xray prefers `certificateFile`. The same applies to `keyFile` and `key`. +::: + +::: tip TIP 4 +When `usage` is `"verify"`, both `keyFile` and `key` may be empty. +::: + +::: tip TIP 5 +You can generate a self-signed CA certificate with `xray tls cert`. +::: + +::: tip TIP 6 +If you already own a domain name, you can conveniently obtain free third-party certificates with tools such as [acme.sh](https://github.com/acmesh-official/acme.sh). +::: + +> `buildChain`: true | false + +Only takes effect when the certificate usage is `issue`. If set to `true`, the CA certificate is embedded into the issued certificate chain. + +::: tip TIP 1 +You should not embed a root certificate into the chain. This option is suitable only when the signing CA certificate is an intermediate certificate. +::: + +> `certificateFile`: string + +Path to the certificate file, for example a `.crt` file generated by OpenSSL. + +> `certificate`: [string] + +An array of strings representing the certificate content, in the same format as the sample above. Choose either `certificate` or `certificateFile`. + +> `keyFile`: string + +Path to the private-key file, for example a `.key` file generated by OpenSSL. Password-protected key files are not currently supported. + +> `key`: [string] + +An array of strings representing the private-key content, in the same format as the sample above. Choose either `key` or `keyFile`.