Skip to main content

Config

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.

Examples​

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: SECRET

Note how we can now have TCP and UDP running on different ports or endpoints.

You can take advantage of 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: *shared

It'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: *shared

In case of blocking of "look-like-nothing" protocols like Shadowsocks, you can use Shadowsocks over Websockets. See the server example 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_SECRET

Note that the Websocket endpoint can, in turn, take an endpoint, which can be used 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_SECRET

Note 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_SECRET

Tunnels​

TunnelConfig​

Tunnel is the top-level object in an Outline configuration. It specifies how the VPN should be configured.

Format: ExplicitTunnelConfig | LegacyShadowsocksConfig | LegacyShadowsocksURI

ExplicitTunnelConfig​

Format: struct

Fields:

  • transport (TransportConfig): the transport to use to exchange packages with the target destination
  • error (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 user
    • details (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 UDP

Error example:

error:
message: Quota exceeded
details: Used 100GB out of 100GB

Transports​

TransportConfig​

Specifies how packets should be exchanged with the target destination.

Format: Interface

Supported Interface types:

TCPUDPConfig​

TCPUDPConfig allows for setting separate TCP and UDP strategies.

Format: struct

Fields:

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
<<: *cipher

Endpoints​

Endpoints establish connections to a fixed endpoint. It's preferable over Dialers since it allows for endpoint-specific optimizations. There are Stream and Packet Endpoints.

EndpointConfig​

Format: string | Interface

The string Endpoint is the host:port address of the selected endpoint. The connection is established using the default Dialer.

Supported Interface types for Stream and Packet Endpoints:

DialEndpointConfig​

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 dial
  • dialer (DialerConfig): the dialer to use to dial the address

WebsocketEndpointConfig​

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 be https or wss for Websocket over TLS, and http or ws for plaintext Websocket.
  • endpoint (EndpointConfig): the web server endpoint to connect to. If absent, is connects to the address specified in the URL.

Dialers​

Dialers establish connections given an endpoint address. There are Stream and Packet Dialers.

DialerConfig​

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 Packet dialers:

Supported Interface types for Stream dialers:

Packet Listeners​

A Packet Listener establishes an unbounded packet connection that can be used to send packets to multiple destinations.

PacketListenerConfig​

Format: null | Interface

The null (absent) Packet Listener means the default Packet Listener, which is a UDP Packet Listener.

Supported Interface types:

Strategies​

Shadowsocks​

LegacyShadowsocksConfig​

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 to
  • server_port (number): the port number to connect to
  • method (string): the AEAD cipher to use
  • password (string): used to generate the encryption key
  • prefix (string): the prefix disguise to use. Supported on stream and packet connections.

Example:

server: example.com
server_port: 4321
method: chacha20-ietf-poly1305
password: SECRET
prefix: "POST "

LegacyShadowsocksURI​

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%20

ShadowsocksConfig​

ShadowsocksConfig 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 to
  • cipher (string): the AEAD cipher to use
  • secret (string): used to generate the encryption key
  • prefix (string, optional): the prefix disguise to use. Supported on stream and packet connections.

Example:

endpoint: example.com:80
cipher: chacha20-ietf-poly1305
secret: SECRET
prefix: "POST "

Selective Routing​

IPTableConfig​

Represents a Stream Dialer that routes connections based on the destination IP address. It matches the destination IP against a list of rules in the table. If a rule matches, the connection is handled by the dialer specified in that rule. If no rules match, the connection is handled by the fallback dialer.

This is a Stream-only dialer and should be used for tcp transports.

Format: struct

Fields:

  • table (list): A list of routing rules.
    • ips (list): A list of IP addresses or CIDR ranges (e.g., 192.0.2.0/24).
    • dialer (DialerConfig): The dialer to use if the destination IP matches an entry in ips.
  • fallback (DialerConfig): The dialer to use if the destination IP does not match any rule in the table.

Example:

# This config blocks TCP connections to 192.0.2.0/24 and sends all
# other TCP traffic directly.
transport:
$type: tcpudp
tcp:
$type: iptable
table:
- ips:
- 192.0.2.0/24
dialer:
$type: block
fallback:
$type: direct
udp:
$type: shadowsocks
# ... udp config

Utility Dialers​

Direct​

Represents a direct Stream dialer.

This is a Stream-only dialer and should be used for tcp transports.

Example:

dialer:
$type: direct

Block​

Represents a dialer that blocks all connection attempts. This can be useful for explicitly denying traffic to specific destinations, especially when used with IPTableConfig.

This is a Stream-only dialer and should be used for tcp transports.

Example:

dialer:
$type: block

Meta Definitions​

FirstSupportedConfig​

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:

Example:

options:
- $type: websocket
url: wss://example.com/SECRET_PATH
- ss.example.com:4321

Interface​

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