Outline uses a YAML-based configuration to define VPN parameters and handle TCP/UDP traffic. The configuration supports composability at multiple levels, enabling flexible and extensible setups.
The top-level configuration specifies a TunnelConfig.
A typical Shadowsocks configuration will look like this:
transport:
$type: tcpudp
tcp:
$type: shadowsocks
endpoint: ss.example.com:4321
cipher: chacha20-ietf-poly1305
secret: SECRET
prefix: "POST "
udp:
$type: shadowsocks
endpoint: ss.example.com:4321
cipher: chacha20-ietf-poly1305
secret: SECRETNote how we can now have TCP and UDP running on different ports or endpoints.
You can leverage YAML anchors and the << merge key to avoid duplication:
transport:
$type: tcpudp
tcp:
<<: &shared
$type: shadowsocks
endpoint: ss.example.com:4321
cipher: chacha20-ietf-poly1305
secret: SECRET
prefix: "POST "
udp: *sharedIt's now possible to compose strategies and do multi-hops:
transport:
$type: tcpudp
tcp:
$type: shadowsocks
endpoint:
$type: dial
address: exit.example.com:4321
dialer:
$type: shadowsocks
address: entry.example.com:4321
cipher: chacha20-ietf-poly1305
secret: ENTRY_SECRET
cipher: chacha20-ietf-poly1305
secret: EXIT_SECRET
udp: *sharedIn case of blocking of "look-like-nothing" protocols like Shadowsocks, you can use Shadowsocks over Websockets. See the server examnple configuration on how to deploy it. A client configuration will look like:
transport:
$type: tcpudp
tcp:
$type: shadowsocks
endpoint:
$type: websocket
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/tcp
cipher: chacha20-ietf-poly1305
secret: SS_SECRET
udp:
$type: shadowsocks
endpoint:
$type: websocket
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/udp
cipher: chacha20-ietf-poly1305
secret: SS_SECRETNote that the Websocket endpoint can, in turn, take an endpoint, which can be leveraged to bypass DNS-based blocking:
transport:
$type: tcpudp
tcp:
$type: shadowsocks
endpoint:
$type: websocket
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/tcp
endpoint: cloudflare.net:443
cipher: chacha20-ietf-poly1305
secret: SS_SECRET
udp:
$type: shadowsocks
endpoint:
$type: websocket
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/udp
endpoint: cloudflare.net:443
cipher: chacha20-ietf-poly1305
secret: SS_SECRETNote that Websockets is not yet supported on Windows. In order to have a single config for all platforms, use a first-supported for backwards-compatibility:
transport:
$type: tcpudp
tcp:
$type: shadowsocks
endpoint:
$type: first-supported
options:
- $type: websocket
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/tcp
- ss.example.com:4321
cipher: chacha20-ietf-poly1305
secret: SS_SECRET
udp:
$type: shadowsocks
endpoint:
$type: first-supported
options:
- $type: websocket
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/udp
- ss.example.com:4321
cipher: chacha20-ietf-poly1305
secret: SS_SECRETIn case the count of users is needed to have an exact estimate of the sessions, a reporting server can be used for that. This feature is currently experimental.
transport:
$type: tcpudp
tcp:
<<: &shared
$type: shadowsocks
endpoint: ss.example.com:4321
cipher: chacha20-ietf-poly1305
secret: SECRET
prefix: "POST "
udp: *shared
reporter:
$type: http
request:
# URL is the only required field.
url: https://your-callback-server.com/outline_callback
method: POST # This is the default, no need to specify
headers:
Content-Type: [application/json]
Authorization: [Bearer SECRET]
body: '{"foo": "bar"}'
# Optional. If not specified reporting happens once at the start of the session.
interval: 24h
# Optional. If enabled, the HTTP client will remember cookies across sessions.
enable_cookies: trueTunnel is the top-level object in the Outline configuration returned by Dynamic Access Keys. It specifies how the VPN should be configured.
Format: ExplicitTunnelConfig | LegacyShadowsocksConfig | LegacyShadowsocksURI
Format: struct
Fields:
transport(TransportConfig): the transport to use to exchange packages with the target destinationerror(struct): information to communicate to the user in case of service error (e.g. key expired, quota exhausted)message(string): user-friendly message to display to the userdetails(string): message to display when the user opens the error details. Helpful for troubleshooting.
Fields error and transport are mutually exclusive.
Successful example:
transport:
$type: tcpudp
tcp:
... # Stream Dialer for TCP
udp:
... # Packet Listener for UDPError example:
error:
message: Quota exceeded
details: Used 100GB out of 100GBSpecifies how packets should be exchanged with the target destination.
Format: Interface
Supported Interface types:
tcpudp: TCPUDPConfig
TCPUDPConfig allows for setting separate TCP and UDP strategies.
Format: struct
Fields:
tcp(DialerConfig): the Stream Dialer to use for TCP connections.udp(PacketListenerConfig): the Packet Listener to use for UDP packets.
Example sending TCP and UDP to different endpoints:
tcp:
$type: shadowsocks
endpoint: ss.example.com:80
<<: &cipher
cipher: chacha20-ietf-poly1305
secret: SECRET
prefix: "POST "
udp:
$type: shadowsocks
endpoint: ss.example.com:53
<<: *cipherEndpoints establish connections to a fixed endpoint. It's preferable over Dialers since it allows for endpoint-specific optimizations. There are Stream and Packet Endpoints.
Format: string | Interface
The string Endpoint is the host:port address of the desired endpoint. The connection is established using the default Dialer.
Supported Interface types for Stream and Packet Endpoints:
dial: DialEndpointConfigfirst-supported: FirstSupportedConfigwebsocket: WebsocketEndpointConfig
Establishes connections by dialing a fixed address. It can take a dialer, which allows for composition of strategies.
Format: struct
Fields:
address(string): the endpoint address to dialdialer(DialerConfig): the dialer to use to dial the address
Tunnels stream and packet connections to an endpoint over Websockets.
For stream connections, each write is turned into a Websocket message. For packet connections, each packet is turned into a Websocket message.
Format: struct
Fields:
url(string): the URL for the Websocket endpoint. The schema must behttpsorwssfor Websocket over TLS, andhttporwsfor plaintext Websocket.endpoint(EndpointConfig): the web server endpoint to connect to. If absent, is connects to the address specified in the URL.
Dialers establishes connections given an endpoint address. There are Stream and Packet Dialers.
Format: null | Interface
The null (absent) Dialer means the default Dialer, which uses direct TCP connections for Stream and direct UDP connections for Packets.
Supported Interface types for Stream and Packer Dialers:
first-supported: FirstSupportedConfigshadowsocks: ShadowsocksConfig
A Packet Listener establishes an unbounded packet connection that can be used to send packets to multiple destinations.
Format: null | Interface
The null (absent) Packet Listener means the default Packet Listener, which is a UDP Packet Listener.
Supported Interface types:
first-supported: FirstSupportedConfigshadowsocks: ShadowsocksPacketListenerConfig
LegacyShadowsocksConfig represents a Tunnel that uses Shadowsocks as the transport. It implements the legacy format for backwards-compatibility.
Format: struct
Fields:
server(string): the host to connect toserver_port(number): the port number to connect tomethod(string): the AEAD cipher to usepassword(string): used to generate the encryption keyprefix(string): the prefix disguise to use. Currently only supported on stream connections.
Example:
server: example.com
server_port: 4321
method: chacha20-ietf-poly1305
password: SECRET
prefix: "POST "LegacyShadowsocksURI represents a Tunnel that uses Shadowsocks as the transport. It implements the legacy URL format for backwards-compatibility.
Format: string
See Legacy Shadowsocks URI Format and SIP002 URI scheme. We don't support plugins.
Example:
ss://chacha20-ietf-poly1305:SECRET@example.com:443?prefix=POST%20ShadowsocksConfig can represent a Stream or Packet Dialers, as well as a Packet Listener that uses Shadowsocks.
Format: struct
Fields:
endpoint(EndpointConfig): the Shadowsocks endpoint to connect tocipher(string): the AEAD cipher to usesecret(string): used to generate the encryption keyprefix(string, optional): the prefix disguise to use. Currently only supported on stream connections.
Example:
endpoint: example.com:4321
cipher: chacha20-ietf-poly1305
secret: SECRET
prefix: "POST "Uses the first config that is supported by the application. This is a way to incorporate new configs while being backwards-compatible with old configs.
Format: struct
Fields:
options(EndpointConfig[] | DialerConfig[] | PacketListenerConfig[]): list of options to consider
Interfaces allow for choosing one of multiple implementations. It uses the $type field to specify the type that config represents.
Example:
$type: shadowsocks
endpoint: example.com:4321
cipher: chacha20-ietf-poly1305
secret: SECRET