TROUBLESHOOTING.md (8632B)
1 # Troubleshooting
2
3 Organised by what you actually see, not by what is actually wrong.
4
5 ---
6
7 ## The client connects to nothing. No error, no server log line — and the real website loads instead.
8
9 This is the worst failure in the whole ecosystem, because everything looks
10 healthy. The server starts clean, the port listens, and every rejected
11 connection falls through to the genuine site your server impersonates, so a
12 browser pointed at your server shows you `www.microsoft.com`.
13
14 First, settle it in one command:
15
16 ```
17 transtation verify
18 ```
19
20 That does a real REALITY handshake against the server's own inbound. If it
21 fails, the problem is the server, not your client — and note that the
22 healthcheck cannot tell you this, because it goes through a loopback inbound
23 that never touches REALITY.
24
25 Causes, in order of likelihood:
26
27 1. **The dest's certificate chain is too big.** Above roughly 5200 bytes the
28 handshake dies partway through the borrowed certificate. `www.microsoft.com`
29 (5879 bytes) is the notable trap — it looks like the safest possible choice
30 and does not work. Check and replace:
31 ```
32 # container
33 docker compose exec proxy xray tls ping www.microsoft.com # look at the chain length
34 echo 'SNI=dl.google.com' >> /opt/transtation/.env
35 cd /opt/transtation && docker compose up -d && transtation verify
36
37 # native
38 /usr/local/lib/transtation/xray tls ping www.microsoft.com
39 echo 'SNI=dl.google.com' >> /etc/transtation/server.env
40 systemctl restart transtation && transtation verify
41 ```
42 Known-good: `dl.google.com` (895), `www.cloudflare.com` (2493),
43 `addons.mozilla.org` (2843), `www.nicovideo.jp` (3822).
44 2. **Wrong `pbk`, `sid` or `sni` in the link.** Regenerate it — never hand-edit
45 it, and never reuse a link from an older install:
46 ```
47 transtation show
48 ```
49 3. **`minClientVer`.** Newer Xray versions default the Reality server to a
50 client-version floor, and a client below it gets exactly this behaviour.
51 transtation pins `minClientVer=0.0.0` so this cannot happen; if you set
52 `MIN_CLIENT_VER` yourself, unset it.
53 4. **Missing `fp` in a hand-built link.** sing-box, NekoBox and Hiddify hard-fail
54 with `uTLS is required by reality client`; Xray-based clients tolerate it.
55 The generated link always carries `fp=chrome`.
56 5. **Your SNI stopped supporting TLS 1.3 or X25519.** Check it and pick another
57 with the same `xray tls ping` command as above.
58
59 ---
60
61 ## `transtation status` says `egress DIRECT — WARP requested but NOT registered`
62
63 Registration failed, and the server started anyway rather than crash-looping.
64 This is not cosmetic: **every packet is leaving from your VPS's own IP**, which
65 is the address tied to your name and payment method.
66
67 ```
68 transtation warp register
69 ```
70
71 Cloudflare rate-limits registration per source IP for about fifteen minutes, so
72 if you have just retried a few times, wait. If it keeps failing, either accept
73 direct egress and silence the warning with `WARP=0` in the config file
74 (`/opt/transtation/.env`, or `/etc/transtation/server.env` on a native install),
75 or check that this host has working outbound HTTPS.
76
77 ---
78
79 ## The container is `unhealthy` (or the native service restarts), but Reality itself works
80
81 Almost always: **your provider blocks outbound UDP/2408**. WARP registration is
82 TCP and succeeds; the data plane is UDP and never comes up.
83
84 ```
85 docker compose logs proxy | grep -o 'Using .* TUN' # container
86 journalctl -u transtation | grep -o 'Using .* TUN' # native
87 ```
88
89 It should print `Using gVisor TUN. NoKernelTun is set to true.` — that is the
90 normal, expected path and it holds even if the container was given extra
91 capabilities. So if you see it, the WireGuard stack is fine and the problem is
92 UDP egress: set `WARP=0` in the config file and restart.
93
94 If instead it prints `Using kernel TUN`, or the container dies with a
95 `read-only file system` error mentioning `rp_filter`, then something removed
96 the `noKernelTun` pin from the generated config. That is a transtation bug —
97 please report it.
98
99 Docker does not restart unhealthy containers by itself. `unhealthy` is a report,
100 not a self-heal. The native install has no healthcheck at all — it is a plain
101 systemd service, so `systemctl status transtation` and the log are the whole
102 story there.
103
104 ---
105
106 ## Clients time out and the server log is completely silent
107
108 Nothing is reaching Xray. The healthcheck cannot detect this — it only proves
109 *outbound* traffic works, and inbound cannot be verified from the server at all.
110
111 1. Open TCP 443 in your **provider's** firewall or security group. This is the
112 answer roughly nine times out of ten.
113 2. Oracle Cloud also needs it opened in the instance's own iptables.
114 3. On the **container** path, Docker's published ports **bypass `ufw`** in both
115 directions, so a ufw rule neither helps nor hurts — do not go looking there.
116 On the **native** path there is no such shortcut: a host firewall does apply,
117 so check `ufw status` / `firewall-cmd --list-all` too.
118 4. Confirm something is actually listening:
119 ```
120 docker compose ps # container
121 systemctl status transtation # native
122 ss -tlnp | grep :443
123 ```
124
125 ---
126
127 ## The client runs, but the host's traffic is untouched
128
129 The installer checks for this and exits non-zero rather than claiming success:
130 if your public address did not move, it says `STILL YOUR OWN ADDRESS`. Start
131 with the log, which names the reason:
132
133 ```
134 journalctl -u transtation-client -n 40
135 ```
136
137 | Message | Meaning |
138 |---|---|
139 | `MODE=tun needs root` | run it with `sudo`. Creating a network interface and routing rules is not something an unprivileged process can do |
140 | `no /dev/net/tun on this host` | the kernel module is not loaded: `sudo modprobe tun && echo tun \| sudo tee /etc/modules-load.d/tun.conf`. Some minimal VPS and container-based hosts (OpenVZ, LXC) do not offer it at all — use proxy mode there |
141 | `iproute2 is not installed` | install it; `ip` is what creates the routes |
142 | `generated config rejected by sing-box` | the share link produced something sing-box will not accept. Reissue it with `transtation show` and never hand-edit it |
143
144 If you installed with `--proxy` instead of the default, this is not a fault:
145 proxy mode opens `127.0.0.1:1080` and deliberately changes nothing else. Only
146 programs you point at it use the tunnel. Reinstall without `--proxy` for a
147 whole-host tunnel.
148
149 ---
150
151 ## The network is completely dead
152
153 ```
154 sudo transtation-panic
155 ```
156
157 It removes the killswitch table, sweeps sing-box's leftover ip rules at
158 priority 9000–9010, flushes routing table 2022 and deletes `tt0`. It needs
159 neither Docker nor a working network.
160
161 If `transtation-panic` is not installed, the same thing by hand:
162
163 ```
164 sudo nft delete table inet transtation
165 # several rules can share one priority, so delete until each one is empty
166 for p in $(seq 9000 9010); do
167 while sudo ip rule del priority $p 2>/dev/null; do :; done
168 done
169 sudo ip link del tt0
170 ```
171
172 Note that a SIGKILLed sing-box leaves those ip rules behind even though the tun
173 device is gone — including `strict_route`'s unreachable rule, which is not bound
174 to the interface. That is why the loop above matters and deleting the interface
175 alone is not enough.
176
177 ---
178
179 ## Everything works except one site, which blocks you
180
181 That is WARP's shared exit pool, not a bug. Either route that site around the
182 tunnel:
183
184 ```
185 DIRECT_SUFFIXES=thatsite.com,othersite.net sudo sh install.sh client
186 ```
187
188 or turn WARP off entirely (`WARP=0`) so you egress from your own VPS address.
189
190 ---
191
192 ## I lost the volume / moved to a new host
193
194 If you have a backup, it is one command into a fresh volume:
195
196 ```
197 cd /opt/transtation && docker compose down # native: systemctl stop transtation
198 transtation restore /root/transtation-backup.tgz
199 docker compose up -d && transtation verify # native: systemctl start transtation
200 ```
201
202 This started life as a documented `tar` one-liner and failed twice in testing,
203 so it is a command now. Getting it right by hand means knowing that Docker
204 seeds a fresh named volume with the ownership of the image directory it is
205 first mounted into — so unpacking with a generic image leaves `/data` owned by
206 root and the server refuses to start — *and* that the backup is mode 0600, so
207 the unpacking container has to run as root to read it at all. `restore` also
208 refuses to run while the server is up, and refuses a file that is not a
209 transtation backup.
210
211 If you do not, there is nothing to recover: a new install generates a new
212 keypair, and every previously issued link is dead. Run `transtation backup` now
213 on the install you still have.