# GFW Workarounds for Chinese Cloud Servers

Network restrictions on Tencent Cloud / Alibaba Cloud: outbound 443 to foreign hosts is unstable or blocked. This reference catalogs what works and what doesn't.

## GitHub Access

### Works ✅

| Method | Command/URL | Notes |
|--------|-------------|-------|
| **GitHub API** | `https://api.github.com` | Separate IP from github.com. Supports full REST API including **write operations** (Contents API for pushing files). See Push via API below. |
| **SSH over 443** | `ssh://git@ssh.github.com:443/owner/repo.git` | Needs SSH key registered on GitHub. Use API to upload key first, then clone. |
| **kkgithub.com** | `https://kkgithub.com/owner/repo.git` | Mirror, but requires authentication for private repos. Non-interactive auth is tricky. |
| **gh CLI token-based** | `gh auth login --with-token` then `gh repo clone` | `gh` may need separate installation. |

### Doesn't Work ❌

| Method | Why |
|--------|-----|
| `github.com` HTTPS | Port 443 TLS handshake fails |
| `gitcode.com` | Only mirrors popular open-source repos, not personal ones |
| `mirror.ghproxy.com` | DNS resolves but connection times out |
| `hub.fastgit.xyz` | Connection times out |
| `gitclone.com` | Read-only; may return 502 but occasionally works (HTTP 200). Push not supported. |
| SSH port 22 | Blocked at ISP level |

### Recommended Workflow

```
1. User provides GitHub Personal Access Token (classic, repo scope)
2. Agent generates SSH key: ssh-keygen -t ed25519
3. Use API to download repo as ZIP first (fastest for public/accessible repos)
4. For private repos: upload SSH key via API, then SSH clone over port 443
```

### Push Files via GitHub Contents API

When `git push` is impossible (github.com blocked), push individual files via the REST API. This works for updating existing files and creating new ones:

```python
import json, base64, urllib.request

TOKEN = "ghp_xxx"
API = "https://api.github.com/repos/OWNER/REPO/contents"

# 1. Get current file SHA (required for updates)
req = urllib.request.Request(f"{API}/path/to/file.ts")
req.add_header("Authorization", f"Bearer {TOKEN}")
req.add_header("Accept", "application/vnd.github+json")
resp = urllib.request.urlopen(req, timeout=15)
sha = json.loads(resp.read()).get("sha")  # None for new files

# 2. Read and encode content
with open("local/path.ts") as f:
    content = base64.b64encode(f.read().encode()).decode()

# 3. PUT the update
body = {"message": "commit message", "content": content, "branch": "main"}
if sha:
    body["sha"] = sha  # Required for existing files, omit for new files

req = urllib.request.Request(f"{API}/path/to/file.ts", method="PUT")
req.add_header("Authorization", f"Bearer {TOKEN}")
req.add_header("Content-Type", "application/json")
urllib.request.urlopen(req, json.dumps(body).encode(), timeout=15)
```

**Key details:**
- `sha` is **required** when updating existing files (422 without it)
- `branch` defaults to the repo's default branch
- File paths must be URL-encoded: `[` → `%5B`, `]` → `%5D`
- The API endpoint is `api.github.com` which is often **not blocked** in China even when `github.com` is

## npm / Node.js

### Works ✅

| Resource | Mirror |
|----------|--------|
| npm registry | `https://registry.npmmirror.com` |
| npm install (JS packages) | `npm config set registry https://registry.npmmirror.com` |

### Doesn't Work ❌

| Package | Why |
|---------|-----|
| `better-sqlite3` | Needs to download prebuilt native binaries from GitHub — blocked. Compilation via node-gyp also fails. |
| Any package with `prebuild-install` | GitHub Releases downloads blocked. |

### Alternative: Use `sql.js`

```bash
npm install sql.js  # Pure WASM, zero native compilation, installs in 1s
```

## pip / Python

| Resource | Mirror |
|----------|--------|
| PyPI | `-i https://mirrors.cloud.tencent.com/pypi/simple` |

## Docker

| Resource | Mirror |
|----------|--------|
| Registry | `https://mirror.ccs.tencentyun.com` in `/etc/docker/daemon.json` |
| Docker CE install | `https://mirrors.cloud.tencent.com/docker-ce/linux/ubuntu` |

## LLM API Access (DeepSeek, OpenAI)

### Validation

API keys may work from your local machine but fail from the server due to key expiration or different network paths. Always validate directly:

```bash
# DeepSeek
curl -s https://api.deepseek.com/v1/chat/completions \
  -H "Authorization: Bearer $DEEPSEEK_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"model":"deepseek-chat","messages":[{"role":"user","content":"hi"}],"max_tokens":10}'

# OpenAI  
curl -s https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"model":"gpt-3.5-turbo","messages":[{"role":"user","content":"hi"}],"max_tokens":10}'
```

If the key is valid but the app still returns 500, check that:
1. The `.env.local` was updated AND the process was restarted (`.env.local` is not hot-reloaded)
2. The old process is truly dead — `fuser -k PORT/tcp` kills all processes on that port
3. The key is being read at module-import time (e.g., `new OpenAI({ apiKey: process.env.X })` on line 1 of `llm.ts`)

## Network Testing Commands

```bash
# Quick connectivity test
curl -sI --connect-timeout 5 https://api.github.com  # Should return 200

# Check which ports are open
ss -tlnp | grep -E '3000|5000|8001|8443'

# Check Cloudflare tunnel logs
cat /tmp/cf-*.log 2>/dev/null | tail -20
```
