Skip to content

Commit e0e9c36

Browse files
jyyi1ohnoroboclaude
authored
Update DevSite articles to match latest versions (#1)
* Update DevSite articles to match latest versions This pull request updates several documentation articles to synchronize them with the latest versions available internally. Some articles had become outdated, and these changes bring in the most current updates. * Revert unnecessary changes * Fix link to Shadowsocks salt documentation * Update Access Key Configuration Reference Add detailed configuration examples and explanations for Outline VPN, including TCP/UDP transport, YAML anchors, and WebSocket support. * Update link for Dynamic Access Keys documentation * Fix capitalization of 'Websockets' in access key config Corrected capitalization of 'Websockets' and 'Websocket' throughout the document for consistency. * Allow known translation diffs for updated VPN docs The English versions of vpn/advanced/prefixing and vpn/reference/access-key-config were updated after translations were exported. Record the expected code block and link count deltas (and the rewritten YAML example in prefixing) so verify_translations passes until new translations land. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Sarah Laplante <laplante@getoutline.org> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cfb55e8 commit e0e9c36

3 files changed

Lines changed: 278 additions & 18 deletions

File tree

docs/vpn/advanced/prefixing.md

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sidebar_label: "Connection Prefixes"
77

88
As of Outline Client version 1.9.0, access keys support the "prefix" option. The
99
"prefix" is a list of bytes used as the first bytes of the
10-
[salt](https://shadowsocks.org/doc/aead.html) of a Shadowsocks TCP connection.
10+
[salt](https://shadowsocks.org/doc/aead.html) of a Shadowsocks connection.
1111
This can make the connection look like a protocol that is allowed in the
1212
network, circumventing firewalls that reject protocols they don't recognize.
1313

@@ -27,9 +27,9 @@ The port you use should match the protocol that your prefix is pretending to be.
2727
IANA keeps a [transport protocol port number registry](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml)
2828
that maps protocols and port numbers.
2929

30-
Some examples of effective prefixes look like common protocols:
30+
Some examples of effective TCP prefixes that look like common protocols:
3131

32-
| | Recommended Port | JSON-encoded | URL-encoded |
32+
| | Recommended Port | YAML-encoded | URL-encoded |
3333
|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|--------------------------|
3434
| HTTP request | 80 (http) | `"POST "` | `POST%20` |
3535
| HTTP response | 80 (http) | `"HTTP/1.1 "` | `HTTP%2F1.1%20` |
@@ -39,22 +39,35 @@ Some examples of effective prefixes look like common protocols:
3939
| 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` |
4040
| SSH | 22 (ssh), 830 (netconf-ssh), 4334 (netconf-ch-ssh), 5162 (snmpssh-trap) | `"SSH-2.0\r\n"` | `SSH-2.0%0D%0A` |
4141

42+
Some examples of effective UDP prefixes that look like common protocols:
43+
44+
| | Recommended Port | YAML-encoded |
45+
|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|
46+
| DNS request | 53 (dns) | `"\u006b\u007b\u0001\u0020"` (note: randomize the first two bytes) |
47+
| DNS response | 53 (dns) | `"\u006b\u007b\u0081\u00a0\u0000\u0001"` (note: randomize the first two bytes) |
48+
| QUIC Client Initial | 443 (https) | `"\u00cd\u0000\u0000\u0000\u0001"` |
49+
4250
### Dynamic Access Keys
4351

4452
To use the prefix feature with [Dynamic Access Keys](../management/dynamic-access-keys.md) (`ssconf://`),
45-
add a "prefix" key to the JSON object, with a **JSON-encoded** value
46-
representing the prefix you want (see examples in the table above). You can
53+
add a "prefix" key to the YAML object, with a **YAML-encoded** value
54+
representing the prefix you want_ (see examples in the table above)_. You can
4755
use escape codes (like \u00FF) to represent non-printable Unicode codepoints in
4856
the `U+0` to `U+FF` range. For example:
4957

50-
```json
51-
{
52-
"server": "example.com",
53-
"server_port": 8388,
54-
"password": "example",
55-
"method": "chacha20-ietf-poly1305",
56-
"prefix": "\u0005\u00DC\u005F\u00E0\u0001\u0020"
57-
}
58+
```yaml
59+
transport:
60+
$type: tcpudp
61+
tcp:
62+
<<: &shared
63+
$type: shadowsocks
64+
endpoint: 147.182.248.224:20478
65+
secret: cqXYJ2BtMyNHneQHjpIXyg
66+
cipher: chacha20-ietf-poly1305
67+
prefix: "\u0013\u0003\u0003\u003F"
68+
udp:
69+
<<: *shared
70+
prefix: "\u006b\u007b\u0001\u0020"
5871
```
5972
6073
### Static Access Keys
@@ -66,6 +79,8 @@ of these in the table above) and add it to the end of the access key like so:
6679
6780
`ss://Z34nthataITHiTNIHTohithITHbVBqQ1o3bkk@127.0.0.1:33142/?outline=1&prefix=<your url-encoded prefix goes here>`
6881

82+
Prefixes in the URL format only work for TCP connections.
83+
6984
For advanced users, you can use your browser's `encodeURIComponent()` function
7085
to convert your **JSON-encoded** prefix to a **URL-encoded** one. To do this,
7186
open your web inspector console
@@ -80,4 +95,4 @@ Press enter. The value produced will be the *URL-encoded *version. For example:
8095
```js
8196
encodeURIComponent("\u0016\u0003\u0001\u0000\u00a8\u0001\u0001")
8297
'%16%03%01%00%C2%A8%01%01'
83-
```
98+
```

docs/vpn/reference/access-key-config.md

Lines changed: 232 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,157 @@ sidebar_label: "Access Key Config"
55

66
# Config
77

8+
Outline uses a YAML-based configuration to define VPN parameters and handle
9+
TCP/UDP traffic. The configuration supports composability at multiple levels,
10+
enabling flexible and extensible setups.
11+
12+
The top-level configuration specifies a [TunnelConfig](#tunnelconfig).
13+
14+
## Examples
15+
16+
A typical Shadowsocks configuration will look like this:
17+
18+
```yaml
19+
transport:
20+
$type: tcpudp
21+
22+
tcp:
23+
$type: shadowsocks
24+
endpoint: ss.example.com:4321
25+
cipher: chacha20-ietf-poly1305
26+
secret: SECRET
27+
prefix: "POST "
28+
29+
udp:
30+
$type: shadowsocks
31+
endpoint: ss.example.com:4321
32+
cipher: chacha20-ietf-poly1305
33+
secret: SECRET
34+
```
35+
36+
Note how we can now have TCP and UDP running on different ports or endpoints.
37+
38+
You can take advantage of YAML anchors and the `<<` merge key to avoid
39+
duplication:
40+
41+
```yaml
42+
transport:
43+
$type: tcpudp
44+
45+
tcp:
46+
<<: &shared
47+
$type: shadowsocks
48+
endpoint: ss.example.com:4321
49+
cipher: chacha20-ietf-poly1305
50+
secret: SECRET
51+
prefix: "POST "
52+
53+
udp: *shared
54+
```
55+
56+
It's now possible to compose strategies and do multi-hops:
57+
58+
```yaml
59+
transport:
60+
$type: tcpudp
61+
62+
tcp:
63+
$type: shadowsocks
64+
65+
endpoint:
66+
$type: dial
67+
address: exit.example.com:4321
68+
dialer:
69+
$type: shadowsocks
70+
address: entry.example.com:4321
71+
cipher: chacha20-ietf-poly1305
72+
secret: ENTRY_SECRET
73+
74+
cipher: chacha20-ietf-poly1305
75+
secret: EXIT_SECRET
76+
77+
udp: *shared
78+
```
79+
80+
In case of blocking of "look-like-nothing" protocols like Shadowsocks, you
81+
can use Shadowsocks over Websockets. See the
82+
[server example configuration](https://github.com/Jigsaw-Code/outline-ss-server/blob/master/cmd/outline-ss-server/config_example.yml)
83+
on how to deploy it. A client configuration will look like:
84+
85+
```yaml
86+
transport:
87+
$type: tcpudp
88+
tcp:
89+
$type: shadowsocks
90+
endpoint:
91+
$type: websocket
92+
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/tcp
93+
cipher: chacha20-ietf-poly1305
94+
secret: SS_SECRET
95+
96+
udp:
97+
$type: shadowsocks
98+
endpoint:
99+
$type: websocket
100+
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/udp
101+
cipher: chacha20-ietf-poly1305
102+
secret: SS_SECRET
103+
```
104+
105+
Note that the Websocket endpoint can, in turn, take an endpoint, which can be
106+
used to bypass DNS-based blocking:
107+
108+
```yaml
109+
transport:
110+
$type: tcpudp
111+
tcp:
112+
$type: shadowsocks
113+
endpoint:
114+
$type: websocket
115+
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/tcp
116+
endpoint: cloudflare.net:443
117+
cipher: chacha20-ietf-poly1305
118+
secret: SS_SECRET
119+
120+
udp:
121+
$type: shadowsocks
122+
endpoint:
123+
$type: websocket
124+
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/udp
125+
endpoint: cloudflare.net:443
126+
cipher: chacha20-ietf-poly1305
127+
secret: SS_SECRET
128+
```
129+
130+
Note that Websockets is not yet supported on Windows. In order to have a single
131+
config for all platforms, use a `first-supported` for backwards-compatibility:
132+
133+
```yaml
134+
transport:
135+
$type: tcpudp
136+
tcp:
137+
$type: shadowsocks
138+
endpoint:
139+
$type: first-supported
140+
options:
141+
- $type: websocket
142+
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/tcp
143+
- ss.example.com:4321
144+
cipher: chacha20-ietf-poly1305
145+
secret: SS_SECRET
146+
147+
udp:
148+
$type: shadowsocks
149+
endpoint:
150+
$type: first-supported
151+
options:
152+
- $type: websocket
153+
url: wss://legendary-faster-packs-und.trycloudflare.com/SECRET_PATH/udp
154+
- ss.example.com:4321
155+
cipher: chacha20-ietf-poly1305
156+
secret: SS_SECRET
157+
```
158+
8159
## Tunnels
9160

10161
### TunnelConfig
@@ -155,11 +306,17 @@ Packet Dialers.
155306
The _null_ (absent) Dialer means the default Dialer, which uses direct TCP
156307
connections for Stream and direct UDP connections for Packets.
157308

158-
Supported Interface types for Stream and Packer Dialers:
309+
Supported Interface types for Stream and Packet dialers:
159310

160311
- `first-supported`: [FirstSupportedConfig](#firstsupportedconfig)
161312
- `shadowsocks`: [ShadowsocksConfig](#shadowsocksconfig)
162313

314+
Supported Interface types for Stream dialers:
315+
316+
- `iptable`: [IPTableConfig](#iptableconfig)
317+
- `direct`: [Direct](#direct)
318+
- `block`: [Block](#block)
319+
163320
## Packet Listeners
164321

165322
A Packet Listener establishes an unbounded packet connection that can be used to
@@ -253,6 +410,79 @@ secret: SECRET
253410
prefix: "POST "
254411
```
255412

413+
### Selective Routing
414+
415+
#### IPTableConfig
416+
417+
Represents a Stream Dialer that routes connections based on the
418+
destination IP address. It matches the destination IP against a list of rules
419+
in the `table`. If a rule matches, the connection is handled by the `dialer`
420+
specified in that rule. If no rules match, the connection is handled by the
421+
`fallback` dialer.
422+
423+
This is a Stream-only dialer and should be used for `tcp` transports.
424+
425+
**Format:** _struct_
426+
427+
**Fields:**
428+
429+
- `table` (*list*): A list of routing rules.
430+
- `ips` (*list*): A list of IP addresses or CIDR ranges (e.g., `192.0.2.0/24`).
431+
- `dialer` ([DialerConfig](#dialerconfig)): The dialer to use if the destination IP matches an entry in `ips`.
432+
- `fallback` ([DialerConfig](#dialerconfig)): The dialer to use if the
433+
destination IP does not match any rule in the `table`.
434+
435+
Example:
436+
437+
```yaml
438+
# This config blocks TCP connections to 192.0.2.0/24 and sends all
439+
# other TCP traffic directly.
440+
transport:
441+
$type: tcpudp
442+
tcp:
443+
$type: iptable
444+
table:
445+
- ips:
446+
- 192.0.2.0/24
447+
dialer:
448+
$type: block
449+
fallback:
450+
$type: direct
451+
udp:
452+
$type: shadowsocks
453+
# ... udp config
454+
```
455+
456+
## Utility Dialers
457+
458+
### Direct
459+
460+
Represents a direct Stream dialer.
461+
462+
This is a Stream-only dialer and should be used for `tcp` transports.
463+
464+
Example:
465+
466+
```yaml
467+
dialer:
468+
$type: direct
469+
```
470+
471+
### Block
472+
473+
Represents a dialer that blocks all connection attempts. This can be useful
474+
for explicitly denying traffic to specific destinations, especially when
475+
used with [IPTableConfig](#iptableconfig).
476+
477+
This is a Stream-only dialer and should be used for `tcp` transports.
478+
479+
Example:
480+
481+
```yaml
482+
dialer:
483+
$type: block
484+
```
485+
256486
## Meta Definitions
257487

258488
### FirstSupportedConfig
@@ -290,4 +520,4 @@ $type: shadowsocks
290520
endpoint: example.com:4321
291521
cipher: chacha20-ietf-poly1305
292522
secret: SECRET
293-
```
523+
```

scripts/verify_translations.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@
5050
"sdk/mobile-app-integration": (16, 14),
5151
# 1 RegisterErrorConfig example added to MD after translation export
5252
"sdk/reference/smart-dialer-config": (10, 9),
53+
# 9 code blocks added to MD after translation export (expanded reference)
54+
"vpn/reference/access-key-config": (17, 8),
55+
}
56+
57+
# Known code block content differences: counts match but the content of
58+
# specific blocks differs because the English example was rewritten after
59+
# translation export. Format: doc_path -> set of block indices (0-based)
60+
# that are allowed to differ.
61+
KNOWN_CODE_BLOCK_CONTENT_DIFFS = {
62+
# English example rewritten from Shadowsocks JSON to transport YAML
63+
# after translation export
64+
"vpn/advanced/prefixing": {0},
5365
}
5466

5567
# Known link count differences: English MD has links (footnotes, escaped
@@ -58,8 +70,8 @@
5870
KNOWN_LINK_COUNT_DIFFS = {
5971
# 2 footnote refs ([^1] in "Alternative[^1]:") not captured by HTML export
6072
"download-links": (14, 12),
61-
# 3 links with escaped brackets in text (e.g. [EndpointConfig\[\]]) not in HTML
62-
"vpn/reference/access-key-config": (31, 28),
73+
# 11 links added to MD after translation export (expanded reference)
74+
"vpn/reference/access-key-config": (39, 28),
6375
# 1 link to advanced-config added to MD after translation export
6476
"vpn/advanced/caddy": (9, 8),
6577
}
@@ -412,8 +424,11 @@ def verify_locale(locale: str, english_paths: set[str]) -> list[Issue]:
412424
f"translation has {len(tr_blocks)}"
413425
))
414426
else:
427+
allowed_block_diffs = KNOWN_CODE_BLOCK_CONTENT_DIFFS.get(doc_path, set())
415428
for idx, (en_block, tr_block) in enumerate(zip(en_blocks, tr_blocks)):
416429
if en_block != tr_block:
430+
if idx in allowed_block_diffs:
431+
continue # Known acceptable content difference
417432
en_lines = en_block.split('\n')
418433
tr_lines = tr_block.split('\n')
419434
diff_line = None

0 commit comments

Comments
 (0)