# Trojan GFW Evasion - Complete Deployment Workflow

## Overview

Trojan is the recommended long-term solution for GFW evasion, proven more stable than WireGuard through Reddit community research (2024-2025).

## Why Trojan Works

- **TLS 1.3 encryption**: Indistinguishable from real HTTPS traffic
- **Port 443**: Standard HTTPS port, DPI treats as legitimate web traffic
- **No VPN fingerprints**: Looks like normal encrypted HTTPS session
- **TCP-based**: Avoids UDP pattern detection

## Reddit Community Consensus

**Real-world success rate (2024-2025):**
- Vanilla WireGuard: ⭐⭐ (often blocked within days)
- WireGuard + port hopping: ⭐⭐⭐ (temporary, requires manual intervention)
- **Trojan (TLS 1.3)**: ⭐⭐⭐⭐⭐⭐ (most stable, rarely blocked)
- **V2Ray/Xray + REALITY**: ⭐⭐⭐⭐ (no cert needed, very stable)
- Shadowsocks: ⭐⭐⭐ (widely used, but less stable than Trojan)

**Key finding**: Port hopping is NOT a long-term solution. GFW detects WireGuard traffic patterns regardless of port. Trojan is superior because it doesn't trigger DPI detection at all.

## Deployment Workflow

### Phase 1: Domain Configuration

1. **Configure DNS A record**
   - Go to Cloudflare / DNS provider
   - Add A record: `@` → `<SERVER_IP>`
   - **Critical**: Set to "DNS only" (grey cloud, NOT orange/proxied)
   - Wait for DNS propagation (1-10 minutes)

2. **Verify DNS**
   ```bash
   dig +short A hot13399.com
   # Should return: 23.94.194.34
   ```

### Phase 2: Trojan Installation

**Method 1: Quick Install (Recommended)**
```bash
# Download and install
curl -fsSL https://raw.githubusercontent.com/trojan-gfw/trojan-quickstart/master/trojan-quickstart.sh -o /tmp/trojan-quickstart.sh
sudo bash /tmp/trojan-quickstart.sh

# Default config location: /usr/local/etc/trojan/config.json
# Default service: systemctl enable/start trojan
```

**Method 2: Let's Encrypt Auto-Setup**
```bash
# Use provided script
bash scripts/setup-trojan-letsencrypt.sh hot13399.com

# This script:
# - Checks DNS resolution
# - Installs Certbot
# - Obtains Let's Encrypt certificate
# - Updates Trojan config
# - Configures auto-renewal
# - Restores WireGuard as backup (port 80)
```

### Phase 3: Multi-Device Configuration

**Why multiple passwords?**
- Independent device management
- Can disable specific devices
- Traffic differentiation in logs
- Better security (one password leak doesn't affect all devices)

**Update Trojan config with password array:**
```json
{
    "password": [
        "F2vhwxP1Vvtc4r+NeIsHFx/s+B7sMGcj/o8OQteFJkY=",  // Android-1
        "M3k9zXpQ4vR7nN8sW2jY6tH0dL5fG3pK=",          // Android-2
        "aB4cD6eF8gH2iJ5kL7mN9oP0qR1sT3uV=",           // iOS
        "xY1zA3cB5dE7fG9hI2jK4lM6nO8pQ0rS="            // Windows
    ]
}
```

**Generate client links:**
```bash
python3 scripts/generate-trojan-links.py hot13399.com

# Output:
# - trojan:// links for each device
# - QR code images (/tmp/trojan-*.png)
# - JSON config file
# - Clash configuration example
```

## Client Configurations

### V2RayNG (Android)

**Import Method 1: Copy Link**
```
Copy: trojan://PASSWORD_ENCODED@hot13399.com:443?sni=hot13399.com&allowInsecure=0&peer=hot13399.com&type=tcp#Trojan-Android-1
Paste in V2RayNG → "+" → "From Clipboard"
```

**Import Method 2: QR Code**
```
1. Open V2RayNG
2. Click "+" or "Add Config"
3. Select "Scan QR Code"
4. Select QR code image (/tmp/trojan-android-1-qr.png)
```

**Configuration Check:**
- ✅ Type: Trojan
- ✅ Server: hot13399.com
- ✅ Port: 443
- ✅ Password: (device-specific)
- ✅ SNI: hot13399.com
- ❌ skip-cert-verify: false (should be false with real cert!)

### Clash (Cross-Platform)

**YAML Configuration:**
```yaml
proxies:
  - name: "Trojan-Android-1"
    type: trojan
    server: hot13399.com
    port: 443
    password: F2vhwxP1Vvtc4r+NeIsHFx/s+B7sMGcj/o8OQteFJkY=
    udp: true
    sni: hot13399.com
    skip-cert-verify: false  # ← Critical: false for real domain cert

  - name: "Trojan-iOS"
    type: trojan
    server: hot13399.com
    port: 443
    password: aB4cD6eF8gH2iJ5kL7mN9oP0qR1sT3uV=
    udp: true
    sni: hot13399.com
    skip-cert-verify: false

proxy-groups:
  - name: "Proxy"
    type: select
    proxies:
      - Trojan-Android-1
      - Trojan-iOS

rules:
  - MATCH,Proxy
```

### Shadowrocket (iOS)

**Manual Configuration:**
```
Type: Trojan
Address: hot13399.com
Port: 443
Password: F2vhwxP1Vvtc4r+NeIsHFx/s+B7sMGcj/o8OQteFJkY=
SNI: hot13399.com
Skip Certificate Verify: OFF (critical for real domain cert!)
```

**Import from Link:**
```
Copy trojan:// link → Shadowrocket → "+" → Import
```

## Certificate Management

### Self-Signed Certificates (Testing)

**Use case**: Initial testing, no domain available

**Client requirement**: MUST enable `skip-cert-verify: true`

**Generate:**
```bash
sudo mkdir -p /etc/trojan-cert
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout /etc/trojan-cert/trojan.key \
  -out /etc/trojan-cert/trojan.crt \
  -subj "/CN=23.94.194.34"
```

### Let's Encrypt Certificates (Production)

**Use case**: Production deployment, better stability

**Client requirement**: `skip-cert-verify: false` (default)

**Auto-renewal setup:**
```bash
# Cron job (added by setup script)
0 3 * * * certbot renew --quiet --post-hook 'systemctl reload trojan'

# Manual test
sudo certbot renew --dry-run
```

**Certificate paths:**
```bash
# Certificate chain (full)
/etc/letsencrypt/live/hot13399.com/fullchain.pem

# Private key
/etc/letsencrypt/live/hot13399.com/privkey.pem
```

## Troubleshooting

### Connection Issues

**Symptom: Client sends but receives nothing**
- Check: DNS resolves correctly (`dig +short A hot13399.com`)
- Check: Trojan service running (`systemctl status trojan`)
- Check: Port 443 listening (`sudo ss -tlnp | grep 443`)
- Check: Certificate valid (`openssl x509 -in /etc/letsencrypt/live/hot13399.com/fullchain.pem -noout -enddate`)

**Symptom: Certificate verify errors**
- Cause: Client has `skip-cert-verify: true` but server uses real cert
- Fix: Set `skip-cert-verify: false` or `verify: true`

**Symptom: "not trojan request" in logs**
- Cause: Direct HTTP access to port 443 (not Trojan)
- Expected: Trojan forwards non-Trojan traffic to fallback server (127.0.0.1:80)
- Action: Ensure web server running on port 80 for fallback

### Multi-Device Issues

**Symptom: Multiple devices can't connect simultaneously**
- Cause: Sharing same password
- Fix: Generate unique passwords, update server config, restart service

**Symptom: All devices disconnected when one connects**
- Cause: IP conflict (using same AllowedIPs in WireGuard, doesn't apply to Trojan)
- Fix: Trojan doesn't have this issue; check for other causes

## Service Management

### Check Status
```bash
# Trojan service
sudo systemctl status trojan

# Port listening
sudo ss -tlnp | grep 443

# Current connections
sudo journalctl -u trojan -f | grep "connected\|disconnected"
```

### Restart Service
```bash
# Graceful restart (preserves connections)
sudo systemctl reload trojan

# Full restart (drops connections)
sudo systemctl restart trojan
```

### View Logs
```bash
# Follow logs in real-time
sudo journalctl -u trojan -f

# Last 50 lines
sudo journalctl -u trojan -n 50 --no-pager

# Filter for errors
sudo journalctl -u trojan -p err -n 20
```

## WireGuard as Backup

**Coexistence Strategy:**
- Trojan: Primary (port 443, domain-based)
- WireGuard: Backup (port 80, IP-based)

**Why keep WireGuard?**
- Performance: Slightly better latency (<1ms vs 2-5ms TLS overhead)
- Failover: Quick fallback if Trojan has issues
- Simple: No certificate management needed

**Config:**
```bash
# WireGuard config: /etc/wireguard/wg0.conf
[Interface]
ListenPort = 80  # Different from Trojan's 443
Address = 10.0.0.1/24

# Client endpoint: <SERVER_IP>:80 (not 443)
```

## Performance Comparison

| Metric | WireGuard (port 80) | Trojan (port 443, domain) |
|---------|----------------------|------------------------------|
| **Protocol** | UDP | TCP/TLS 1.3 |
| **Latency overhead** | <1ms | 2-5ms (TLS handshake) |
| **Anti-DPI** | ❌ Easily detected | ✅ Indistinguishable |
| **Stability** | ⚠️ Days before block | ✅ Months stable |
| **Certificate** | Not needed | Let's Encrypt required |
| **Client setup** | Simple | Simple (trojan:// links) |
| **Multi-device** | IP conflicts (tricky) | ✅ Independent passwords |

## Real-World Case Study

**Deployment Date**: 2026-05-01
**Domain**: hot13399.com
**Certificate**: Let's Encrypt (expires 2026-07-30)
**Devices Configured**: 4 (Android-1, Android-2, iOS, Windows)
**Backup**: WireGuard on port 80

**Results:**
- ✅ DNS resolution: hot13399.com → 23.94.194.34
- ✅ Let's Encrypt certificate obtained successfully
- ✅ Trojan config updated with real cert
- ✅ TLS handshake verified (return code: 0 ok)
- ✅ Multi-device passwords configured
- ✅ Auto-renewal configured (daily 3:00 AM)
- ✅ V2RayNG links generated with QR codes
- ✅ WireGuard restored as backup (port 80)

**Client Import Methods:**
- ✅ V2RayNG: trojan:// links + QR codes
- ✅ Clash: YAML configuration with skip-cert-verify: false
- ✅ Shadowrocket: Manual config + link import

**Critical Settings Verified:**
- ✅ allowInsecure=0 (no skip-cert-verify for real cert)
- ✅ SNI=hot13399.com (domain, not IP)
- ✅ verify_hostname=true (in server config)

## Scripts Available

1. **setup-trojan-letsencrypt.sh**: Automated Let's Encrypt + Trojan setup
2. **generate-trojan-links.py**: Multi-device link + QR code generator
3. **check-trojan.sh**: Service status verification (in main skill)

## References

- Reddit research: r/WireGuard, r/selfhosted, r/dumbclub (2024-2025)
- Trojan official: https://trojan-gfw.github.io/trojan/
- Let's Encrypt: https://letsencrypt.org/docs/
- V2RayNG: https://github.com/2dust/v2rayNG
