Connection Prefix Disguises
Stay organized with collections
Save and categorize content based on your preferences.
As of Outline Client version 1.9.0, access keys support the "prefix" option. The
"prefix" is a list of bytes used as the first bytes of the
salt of a Shadowsocks connection.
This can make the connection look like a protocol that is allowed in the
network, circumventing firewalls that reject protocols they don't recognize.
When should I try this?
If you suspect the users of your Outline deployment are still being blocked, you
may want to consider trying a few different prefixes.
Instructions
The prefix should be no longer than 16 bytes. Longer prefixes may cause salt
collisions, which can compromise the encryption safety and cause connections to
be detected. Use the shortest prefix you can to bypass the blocking you are
facing.
The port you use should match the protocol that your prefix is pretending to be.
IANA keeps a transport protocol port number registry
that maps protocols and port numbers.
Some examples of effective TCP prefixes that look like common protocols:
|
Recommended Port |
YAML-encoded |
URL-encoded |
HTTP request |
80 (http) |
"POST " |
POST%20 |
HTTP response |
80 (http) |
"HTTP/1.1 " |
HTTP%2F1.1%20 |
DNS-over-TCP request |
53 (dns) |
"\u0005\u00DC\u005F\u00E0\u0001\u0020" |
%05%C3%9C_%C3%A0%01%20 |
TLS ClientHello |
443 (https), 463 (smtps), 563 (nntps), 636 (ldaps), 989 (ftps-data), 990 (ftps), 993 (imaps), 995 (pop3s), 5223 (Apple APN), 5228 (Play Store), 5349 (turns) |
"\u0016\u0003\u0001\u0000\u00a8\u0001\u0001" |
%16%03%01%00%C2%A8%01%01 |
TLS Application Data |
443 (https), 463 (smtps), 563 (nntps), 636 (ldaps), 989 (ftps-data), 990 (ftps), 993 (imaps), 995 (pop3s), 5223 (Apple APN), 5228 (Play Store), 5349 (turns) |
"\u0013\u0003\u0003\u003F" |
%13%03%03%3F |
TLS ServerHello |
443 (https), 463 (smtps), 563 (nntps), 636 (ldaps), 989 (ftps-data), 990 (ftps), 993 (imaps), 995 (pop3s), 5223 (Apple APN), 5228 (Play Store), 5349 (turns) |
"\u0016\u0003\u0003\u0040\u0000\u0002" |
%16%03%03%40%00%02 |
SSH |
22 (ssh), 830 (netconf-ssh), 4334 (netconf-ch-ssh), 5162 (snmpssh-trap) |
"SSH-2.0\r\n" |
SSH-2.0%0D%0A |
Some examples of effective UDP prefixes that look like common protocols:
|
Recommended Port |
YAML-encoded |
DNS request |
53 (dns) |
"\u006b\u007b\u0001\u0020" (note: randomize the first two bytes) |
DNS response |
53 (dns) |
"\u006b\u007b\u0081\u00a0\u0000\u0001" (note: randomize the first two bytes) |
QUIC Client Initial |
443 (https) |
"\u00cd\u0000\u0000\u0000\u0001" |
Dynamic Access Keys
To use the prefix feature with Dynamic Access Keys (ssconf://
),
add a "prefix" key to the YAML object, with a YAML-encoded value
representing the prefix you want_ (see examples in the table above)_. You can
use escape codes (like \u00FF) to represent non-printable Unicode codepoints in
the U+0
to U+FF
range. For example:
transport:
$type: tcpudp
tcp:
<<: &shared
$type: shadowsocks
endpoint: 147.182.248.224:20478
secret: cqXYJ2BtMyNHneQHjpIXyg
cipher: chacha20-ietf-poly1305
prefix: "\u0013\u0003\u0003\u003F"
udp:
<<: *shared
prefix: "\u006b\u007b\u0001\u0020"
Static Access Keys
To use prefixes with Static Access Keys (ss://), you'll need to modify your
existing key before distributing it. If you have a Static Access Key generated
by Outline Manager, grab a URL-encoded version of your prefix (see examples
of these in the table above) and add it to the end of the access key like so:
ss://Z34nthataITHiTNIHTohithITHbVBqQ1o3bkk@127.0.0.1:33142/?outline=1&prefix=<your url-encoded prefix goes here>
Prefixes in the URL format only work for TCP connections.
For advanced users, you can use your browser's encodeURIComponent()
function
to convert your JSON-encoded prefix to a URL-encoded one. To do this,
open your web inspector console
(*Developer > Javascript Web Console *on Chrome), and type the following:
encodeURIComponent("<your json-encoded prefix goes here>")
Press enter. The value produced will be the *URL-encoded *version. For example:
encodeURIComponent("\u0016\u0003\u0001\u0000\u00a8\u0001\u0001")
'%16%03%01%00%C2%A8%01%01'
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-08-08 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-08 UTC."],[[["\u003cp\u003eOutline Client version 1.9.0 and later supports the "prefix" option for access keys, allowing users to define a sequence of bytes at the beginning of the Shadowsocks TCP connection salt.\u003c/p\u003e\n"],["\u003cp\u003eThe "prefix" feature is designed to help bypass firewalls by making connections appear to use a recognized protocol, and is useful if users are being blocked.\u003c/p\u003e\n"],["\u003cp\u003ePrefixes should not exceed 16 bytes to avoid salt collisions and potential compromise of encryption, with shorter prefixes being recommended.\u003c/p\u003e\n"],["\u003cp\u003eThe selected port should align with the protocol the prefix is mimicking, and several examples of effective prefixes are provided for common protocols like HTTP, DNS, TLS, and SSH.\u003c/p\u003e\n"],["\u003cp\u003eDynamic Access Keys require adding a JSON-encoded "prefix" key, while Static Access Keys need the URL-encoded prefix appended to the key, and a browser's \u003ccode\u003eencodeURIComponent()\u003c/code\u003e function can convert between the two formats.\u003c/p\u003e\n"]]],["Outline Client version 1.9.0 and later supports the \"prefix\" option for access keys. Prefixes are byte lists placed at the beginning of the Shadowsocks TCP connection salt, masking the connection as a recognized protocol. To implement, select a prefix (max 16 bytes) resembling a common protocol (e.g., \"HTTP/1.1 \") and a matching port from IANA. Dynamic Access Keys use JSON-encoded prefixes, while Static Access Keys require URL-encoded prefixes added to the access key URL.\n"],null,["# Connection Prefix Disguises\n\nAs of Outline Client version 1.9.0, access keys support the \"prefix\" option. The\n\"prefix\" is a list of bytes used as the first bytes of the\n[salt](https://shadowsocks.org/guide/aead.html) of a Shadowsocks connection.\nThis can make the connection look like a protocol that is allowed in the\nnetwork, circumventing firewalls that reject protocols they don't recognize.\n\nWhen should I try this?\n-----------------------\n\nIf you suspect the users of your Outline deployment are still being blocked, you\nmay want to consider trying a few different prefixes.\n\nInstructions\n------------\n\nThe prefix should be no longer than 16 bytes. Longer prefixes may cause salt\ncollisions, which can compromise the encryption safety and cause connections to\nbe detected. Use the shortest prefix you can to bypass the blocking you are\nfacing.\n\nThe port you use should match the protocol that your prefix is pretending to be.\nIANA keeps a [transport protocol port number registry](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml)\nthat maps protocols and port numbers.\n\nSome examples of effective TCP prefixes that look like common protocols:\n\n| | Recommended Port | YAML-encoded | URL-encoded |\n|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------|----------------------------|\n| HTTP request | 80 (http) | `\"POST \"` | `POST%20` |\n| HTTP response | 80 (http) | `\"HTTP/1.1 \"` | `HTTP%2F1.1%20` |\n| DNS-over-TCP request | 53 (dns) | `\"\\u0005\\u00DC\\u005F\\u00E0\\u0001\\u0020\"` | `%05%C3%9C_%C3%A0%01%20` |\n| TLS ClientHello | 443 (https), 463 (smtps), 563 (nntps), 636 (ldaps), 989 (ftps-data), 990 (ftps), 993 (imaps), 995 (pop3s), 5223 (Apple APN), 5228 (Play Store), 5349 (turns) | `\"\\u0016\\u0003\\u0001\\u0000\\u00a8\\u0001\\u0001\"` | `%16%03%01%00%C2%A8%01%01` |\n| TLS Application Data | 443 (https), 463 (smtps), 563 (nntps), 636 (ldaps), 989 (ftps-data), 990 (ftps), 993 (imaps), 995 (pop3s), 5223 (Apple APN), 5228 (Play Store), 5349 (turns) | `\"\\u0013\\u0003\\u0003\\u003F\"` | `%13%03%03%3F` |\n| TLS ServerHello | 443 (https), 463 (smtps), 563 (nntps), 636 (ldaps), 989 (ftps-data), 990 (ftps), 993 (imaps), 995 (pop3s), 5223 (Apple APN), 5228 (Play Store), 5349 (turns) | `\"\\u0016\\u0003\\u0003\\u0040\\u0000\\u0002\"` | `%16%03%03%40%00%02` |\n| SSH | 22 (ssh), 830 (netconf-ssh), 4334 (netconf-ch-ssh), 5162 (snmpssh-trap) | `\"SSH-2.0\\r\\n\"` | `SSH-2.0%0D%0A` |\n\nSome examples of effective UDP prefixes that look like common protocols:\n\n| | Recommended Port | YAML-encoded |\n|---------------------|------------------|--------------------------------------------------------------------------------|\n| DNS request | 53 (dns) | `\"\\u006b\\u007b\\u0001\\u0020\"` (note: randomize the first two bytes) |\n| DNS response | 53 (dns) | `\"\\u006b\\u007b\\u0081\\u00a0\\u0000\\u0001\"` (note: randomize the first two bytes) |\n| QUIC Client Initial | 443 (https) | `\"\\u00cd\\u0000\\u0000\\u0000\\u0001\"` |\n\n### Dynamic Access Keys\n\nTo use the prefix feature with [Dynamic Access Keys](/outline/docs/guides/service-providers/dynamic-access-keys) (`ssconf://`),\nadd a \"prefix\" key to the YAML object, with a **YAML-encoded** value\nrepresenting the prefix you want_ (see examples in the table above)_. You can\nuse escape codes (like \\\\u00FF) to represent non-printable Unicode codepoints in\nthe `U+0` to `U+FF` range. For example: \n\n transport:\n $type: tcpudp\n tcp:\n \u003c\u003c: &shared\n $type: shadowsocks\n endpoint: 147.182.248.224:20478\n secret: cqXYJ2BtMyNHneQHjpIXyg\n cipher: chacha20-ietf-poly1305\n prefix: \"\\u0013\\u0003\\u0003\\u003F\"\n udp:\n \u003c\u003c: *shared\n prefix: \"\\u006b\\u007b\\u0001\\u0020\"\n\n### Static Access Keys\n\nTo use prefixes with **Static Access Keys** (ss://), you'll need to modify your\nexisting key before distributing it. If you have a Static Access Key generated\nby Outline Manager, grab a **URL-encoded** version of your prefix (see examples\nof these in the table above) and add it to the end of the access key like so:\n\n`ss://Z34nthataITHiTNIHTohithITHbVBqQ1o3bkk@127.0.0.1:33142/?outline=1&prefix=\u003cyour url-encoded prefix goes here\u003e`\n\nPrefixes in the URL format only work for TCP connections.\n\nFor advanced users, you can use your browser's `encodeURIComponent()` function\nto convert your **JSON-encoded** prefix to a **URL-encoded** one. To do this,\nopen your web inspector console\n(\\*Developer \\\u003e Javascript Web Console \\*on Chrome), and type the following: \n\n encodeURIComponent(\"\u003cyour json-encoded prefix goes here\u003e\")\n\nPress enter. The value produced will be the \\*URL-encoded \\*version. For example: \n\n encodeURIComponent(\"\\u0016\\u0003\\u0001\\u0000\\u00a8\\u0001\\u0001\")\n '%16%03%01%00%C2%A8%01%01'"]]