gooserelayvpn-socks5-tunnel
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGooseRelayVPN SOCKS5 Tunnel Skill
GooseRelayVPN SOCKS5 隧道技能
What It Does
功能介绍
GooseRelayVPN is a SOCKS5 proxy that tunnels raw TCP through a Google Apps Script web app to a self-hosted VPS exit server. The traffic path:
Browser/App
-> SOCKS5 (127.0.0.1:1080)
-> AES-256-GCM encrypted frames
-> HTTPS to Google edge IP (SNI=www.google.com, Host=script.google.com)
-> Apps Script doPost() — dumb forwarder, never sees plaintext
-> Your VPS :8443/tunnel — decrypts, dials real target
<- Same path in reverse via long-pollingKey properties:
- Domain fronting: TLS SNI shows ; actual host is
www.google.comscript.google.com - End-to-end AES-256-GCM: Google never holds the key
- Raw TCP tunneling: SSH, IMAP, custom protocols — anything SOCKS5 carries
- Multi-deployment load balancing: Round-robin + health-aware blacklist across multiple Apps Script deployments
GooseRelayVPN是一款SOCKS5代理,通过Google Apps Script Web应用将原始TCP流量隧道传输到自行托管的VPS出口服务器。流量路径:
Browser/App
-> SOCKS5 (127.0.0.1:1080)
-> AES-256-GCM加密帧
-> HTTPS到Google边缘IP(SNI=www.google.com,Host=script.google.com)
-> Apps Script doPost() — 仅做转发,不会看到明文
-> 你的VPS :8443/tunnel — 解密,连接真实目标
<- 通过长轮询沿原路返回关键特性:
- 域名前置:TLS SNI显示;实际主机为
www.google.comscript.google.com - 端到端AES-256-GCM加密:Google不会持有密钥
- 原始TCP隧道:支持SSH、IMAP、自定义协议——任何SOCKS5可承载的流量
- 多部署负载均衡:在多个Apps Script部署间实现轮询+健康感知黑名单机制
Architecture Overview
架构概述
| Component | Location | Purpose |
|---|---|---|
| Local machine | SOCKS5 listener, AES encrypt, HTTPS relay |
| Google Apps Script | Google cloud (free) | Dumb HTTP forwarder, domain-fronting layer |
| Your VPS | AES decrypt, TCP dial to real targets |
| 组件 | 位置 | 用途 |
|---|---|---|
| 本地机器 | SOCKS5监听器,AES加密,HTTPS转发 |
| Google Apps Script | Google云端(免费) | 简易HTTP转发器,域名前置层 |
| 你的VPS | AES解密,TCP连接真实目标 |
Installation
安装
Option A: Pre-built Binaries
选项A:预编译二进制文件
bash
undefinedbash
undefinedClient (local machine) - Linux example
Client (local machine) - Linux example
wget https://github.com/kianmhz/GooseRelayVPN/releases/latest/download/GooseRelayVPN-client-vX.Y.Z-linux-amd64.tar.gz
tar -xzf GooseRelayVPN-client-vX.Y.Z-linux-amd64.tar.gz
wget https://github.com/kianmhz/GooseRelayVPN/releases/latest/download/GooseRelayVPN-client-vX.Y.Z-linux-amd64.tar.gz
tar -xzf GooseRelayVPN-client-vX.Y.Z-linux-amd64.tar.gz
Server (VPS)
Server (VPS)
wget https://github.com/kianmhz/GooseRelayVPN/releases/latest/download/GooseRelayVPN-server-vX.Y.Z-linux-amd64.tar.gz
tar -xzf GooseRelayVPN-server-vX.Y.Z-linux-amd64.tar.gz
Platform suffixes: `windows-amd64`, `darwin-amd64`, `darwin-arm64`, `linux-amd64`, `android-arm64`wget https://github.com/kianmhz/GooseRelayVPN/releases/latest/download/GooseRelayVPN-server-vX.Y.Z-linux-amd64.tar.gz
tar -xzf GooseRelayVPN-server-vX.Y.Z-linux-amd64.tar.gz
平台后缀:`windows-amd64`, `darwin-amd64`, `darwin-arm64`, `linux-amd64`, `android-arm64`Option B: Build from Source (Go 1.22+)
选项B:从源码构建(Go 1.22+)
bash
git clone https://github.com/kianmhz/GooseRelayVPN.git
cd GooseRelayVPNbash
git clone https://github.com/kianmhz/GooseRelayVPN.git
cd GooseRelayVPNBuild both binaries
Build both binaries
go build -o goose-client ./cmd/client
go build -o goose-server ./cmd/server
go build -o goose-client ./cmd/client
go build -o goose-server ./cmd/server
Cross-compile for Linux VPS from macOS/Windows
Cross-compile for Linux VPS from macOS/Windows
GOOS=linux GOARCH=amd64 go build -o goose-server-linux ./cmd/server
---GOOS=linux GOARCH=amd64 go build -o goose-server-linux ./cmd/server
---Quick Start
快速开始
Step 1: Generate Secret Key
步骤1:生成密钥
bash
bash scripts/gen-key.shbash
bash scripts/gen-key.shOutputs a 64-character hex string — use this as tunnel_key in both configs
输出64位十六进制字符串 — 在两个配置文件中都将其用作tunnel_key
Or generate manually:
```bash
openssl rand -hex 32
或手动生成:
```bash
openssl rand -hex 32Step 2: Configure Client
步骤2:配置客户端
client_config.jsonjson
{
"socks_host": "127.0.0.1",
"socks_port": 1080,
"google_host": "216.239.38.120",
"sni": "www.google.com",
"script_keys": ["YOUR_APPS_SCRIPT_DEPLOYMENT_ID"],
"tunnel_key": "YOUR_64_CHAR_HEX_KEY"
}client_config.jsonjson
{
"socks_host": "127.0.0.1",
"socks_port": 1080,
"google_host": "216.239.38.120",
"sni": "www.google.com",
"script_keys": ["YOUR_APPS_SCRIPT_DEPLOYMENT_ID"],
"tunnel_key": "YOUR_64_CHAR_HEX_KEY"
}Step 3: Configure Server
步骤3:配置服务器
server_config.jsonjson
{
"server_host": "0.0.0.0",
"server_port": 8443,
"tunnel_key": "SAME_64_CHAR_HEX_KEY_AS_CLIENT"
}server_config.jsonjson
{
"server_host": "0.0.0.0",
"server_port": 8443,
"tunnel_key": "SAME_64_CHAR_HEX_KEY_AS_CLIENT"
}Step 4: Deploy Google Apps Script
步骤4:部署Google Apps Script
- Go to script.google.com → New project
- Replace default code with contents
apps_script/Code.gs - Edit the VPS URL line:
javascript
const VPS_URL = 'http://YOUR_VPS_PUBLIC_IP:8443/tunnel'; - Deploy → New deployment → Type: Web app
- Execute as: Me
- Who has access: Anyone
- Copy the Deployment ID → paste into in client config
script_keys
⚠️ Every code edit requires a new deployment (not just saving). Old deployment IDs stop working if you only save without redeploying.
- 访问script.google.com → 新建项目
- 将默认代码替换为中的内容
apps_script/Code.gs - 编辑VPS URL行:
javascript
const VPS_URL = 'http://YOUR_VPS_PUBLIC_IP:8443/tunnel'; - 部署 → 新建部署 → 类型:Web应用
- 执行方式:我
- 访问权限:任何人
- 复制部署ID → 粘贴到客户端配置的中
script_keys
⚠️ 每次代码编辑都需要创建新部署(不仅仅是保存)。如果仅保存而不重新部署,旧部署ID将失效。
Step 5: Open VPS Firewall
步骤5:开放VPS防火墙
bash
undefinedbash
undefinedUFW
UFW
sudo ufw allow 8443/tcp
sudo ufw allow 8443/tcp
Verify from local machine
从本地机器验证
curl http://YOUR_VPS_IP:8443/healthz
curl http://YOUR_VPS_IP:8443/healthz
Expected: HTTP 200 empty body
预期结果:HTTP 200 空响应体
Also check cloud provider firewall (AWS Security Groups, DigitalOcean Firewall, etc.) for inbound TCP 8443.
同时检查云服务商防火墙(AWS安全组、DigitalOcean防火墙等)是否允许TCP 8443入站流量。Step 6: Run Server on VPS
步骤6:在VPS上运行服务器
bash
./goose-server -config server_config.jsonbash
./goose-server -config server_config.jsonStep 7: Run Client Locally
步骤7:在本地运行客户端
bash
./goose-client -config client_config.jsonExpected output:
CLIENT INFO GooseRelayVPN client starting
CLIENT INFO SOCKS5 proxy: socks5://127.0.0.1:1080
CLIENT INFO pre-flight OK: relay healthy, AES key matches end-to-end
CLIENT INFO ready: local SOCKS5 is listening on 127.0.0.1:1080bash
./goose-client -config client_config.json预期输出:
CLIENT INFO GooseRelayVPN client starting
CLIENT INFO SOCKS5 proxy: socks5://127.0.0.1:1080
CLIENT INFO pre-flight OK: relay healthy, AES key matches end-to-end
CLIENT INFO ready: local SOCKS5 is listening on 127.0.0.1:1080CLI Reference
CLI参考
bash
undefinedbash
undefinedClient
Client
./goose-client -config client_config.json
./goose-client -config /path/to/custom_client.json
./goose-client -config client_config.json
./goose-client -config /path/to/custom_client.json
Server
Server
./goose-server -config server_config.json
./goose-server -config /path/to/custom_server.json
Both binaries take only `-config` flag pointing to their respective JSON config file.
---./goose-server -config server_config.json
./goose-server -config /path/to/custom_server.json
两个二进制文件仅接受指向各自JSON配置文件的`-config`参数。
---Configuration Reference
配置参考
Client Config (client_config.json
)
client_config.json客户端配置(client_config.json
)
client_config.json| Field | Type | Description |
|---|---|---|
| string | SOCKS5 listener address. Use |
| int | SOCKS5 listener port (default: |
| string | Google edge IP for domain fronting (e.g. |
| string | TLS SNI value (must be |
| []string | One or more Apps Script Deployment IDs or full |
| string | 64-char hex AES-256 key — must match server |
| 字段 | 类型 | 描述 |
|---|---|---|
| string | SOCKS5监听地址。使用 |
| int | SOCKS5监听端口(默认: |
| string | 用于域名前置的Google边缘IP(例如 |
| string | TLS SNI值(必须为 |
| []string | 一个或多个Apps Script部署ID或完整的 |
| string | 64位十六进制AES-256密钥 — 必须与服务器端一致 |
Server Config (server_config.json
)
server_config.json服务器配置(server_config.json
)
server_config.json| Field | Type | Description |
|---|---|---|
| string | Bind address on VPS (use |
| int | Listen port (default: |
| string | 64-char hex AES-256 key — must match client |
| 字段 | 类型 | 描述 |
|---|---|---|
| string | VPS上的绑定地址(使用 |
| int | 监听端口(默认: |
| string | 64位十六进制AES-256密钥 — 必须与客户端一致 |
Multiple Deployments (Scaling)
多部署(扩容)
Each Apps Script deployment handles ~20,000 calls/day. Add multiple deployment IDs to scale:
json
{
"socks_host": "127.0.0.1",
"socks_port": 1080,
"google_host": "216.239.38.120",
"sni": "www.google.com",
"script_keys": [
"AKfycbx_DEPLOYMENT_ID_ONE_xxxx",
"AKfycbx_DEPLOYMENT_ID_TWO_xxxx",
"AKfycbx_DEPLOYMENT_ID_THREE_xxxx"
],
"tunnel_key": "YOUR_64_CHAR_HEX_KEY"
}The client automatically:
- Round-robins across all deployments
- Backs off failing deployments (3s → 6s → 12s → up to ~48s)
- Retries failed polls on another deployment in the same cycle
All deployments point to the same VPS and use the same .
tunnel_key每个Apps Script部署每天可处理约20,000次调用。添加多个部署ID可实现扩容:
json
{
"socks_host": "127.0.0.1",
"socks_port": 1080,
"google_host": "216.239.38.120",
"sni": "www.google.com",
"script_keys": [
"AKfycbx_DEPLOYMENT_ID_ONE_xxxx",
"AKfycbx_DEPLOYMENT_ID_TWO_xxxx",
"AKfycbx_DEPLOYMENT_ID_THREE_xxxx"
],
"tunnel_key": "YOUR_64_CHAR_HEX_KEY"
}客户端会自动:
- 在所有部署间轮询
- 对失败的部署进行退避(3秒→6秒→12秒→最长约48秒)
- 在同一周期内尝试在其他部署上重试失败的轮询
所有部署都指向同一个VPS并使用相同的。
tunnel_keySystemd Service (VPS)
Systemd服务(VPS)
bash
sudo nano /etc/systemd/system/goose-relay.serviceini
[Unit]
Description=GooseRelayVPN exit server
After=network.target
[Service]
Type=simple
WorkingDirectory=/root
ExecStart=/root/goose-server -config /root/server_config.json
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetbash
sudo systemctl daemon-reload
sudo systemctl enable goose-relay
sudo systemctl start goose-relay
sudo systemctl status goose-relay --no-pagerbash
sudo nano /etc/systemd/system/goose-relay.serviceini
[Unit]
Description=GooseRelayVPN exit server
After=network.target
[Service]
Type=simple
WorkingDirectory=/root
ExecStart=/root/goose-server -config /root/server_config.json
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetbash
sudo systemctl daemon-reload
sudo systemctl enable goose-relay
sudo systemctl start goose-relay
sudo systemctl status goose-relay --no-pagerView logs
查看日志
journalctl -u goose-relay -f
---journalctl -u goose-relay -f
---Google Apps Script (Code.gs
)
Code.gsGoogle Apps Script(Code.gs
)
Code.gsThe Apps Script is a thin forwarder. Key structure to understand:
javascript
// apps_script/Code.gs — dumb forwarder pattern
const VPS_URL = 'http://YOUR_VPS_PUBLIC_IP:8443/tunnel';
function doPost(e) {
// Forwards request body verbatim to VPS
// Never decrypts — AES key never touches Google
const response = UrlFetchApp.fetch(VPS_URL, {
method: 'post',
payload: e.postData.contents,
headers: { 'Content-Type': 'application/octet-stream' },
muteHttpExceptions: true
});
return ContentService.createTextOutput(response.getContent())
.setMimeType(ContentService.MimeType.OCTET_STREAM);
}Apps Script是一个轻量转发器。核心结构如下:
javascript
// apps_script/Code.gs — dumb forwarder pattern
const VPS_URL = 'http://YOUR_VPS_PUBLIC_IP:8443/tunnel';
function doPost(e) {
// Forwards request body verbatim to VPS
// Never decrypts — AES key never touches Google
const response = UrlFetchApp.fetch(VPS_URL, {
method: 'post',
payload: e.postData.contents,
headers: { 'Content-Type': 'application/octet-stream' },
muteHttpExceptions: true
});
return ContentService.createTextOutput(response.getContent())
.setMimeType(ContentService.MimeType.OCTET_STREAM);
}Code Examples
代码示例
Programmatic Config Generation (Go)
程序化配置生成(Go)
go
package main
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"os"
)
type ClientConfig struct {
SocksHost string `json:"socks_host"`
SocksPort int `json:"socks_port"`
GoogleHost string `json:"google_host"`
SNI string `json:"sni"`
ScriptKeys []string `json:"script_keys"`
TunnelKey string `json:"tunnel_key"`
}
type ServerConfig struct {
ServerHost string `json:"server_host"`
ServerPort int `json:"server_port"`
TunnelKey string `json:"tunnel_key"`
}
func generateTunnelKey() (string, error) {
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
func main() {
key, err := generateTunnelKey()
if err != nil {
panic(err)
}
clientCfg := ClientConfig{
SocksHost: "127.0.0.1",
SocksPort: 1080,
GoogleHost: "216.239.38.120",
SNI: "www.google.com",
ScriptKeys: []string{os.Getenv("APPS_SCRIPT_DEPLOYMENT_ID")},
TunnelKey: key,
}
serverCfg := ServerConfig{
ServerHost: "0.0.0.0",
ServerPort: 8443,
TunnelKey: key,
}
clientJSON, _ := json.MarshalIndent(clientCfg, "", " ")
serverJSON, _ := json.MarshalIndent(serverCfg, "", " ")
os.WriteFile("client_config.json", clientJSON, 0600)
os.WriteFile("server_config.json", serverJSON, 0600)
fmt.Printf("Generated key: %s\n", key)
fmt.Println("Configs written to client_config.json and server_config.json")
}go
package main
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"os"
)
type ClientConfig struct {
SocksHost string `json:"socks_host"`
SocksPort int `json:"socks_port"`
GoogleHost string `json:"google_host"`
SNI string `json:"sni"`
ScriptKeys []string `json:"script_keys"`
TunnelKey string `json:"tunnel_key"`
}
type ServerConfig struct {
ServerHost string `json:"server_host"`
ServerPort int `json:"server_port"`
TunnelKey string `json:"tunnel_key"`
}
func generateTunnelKey() (string, error) {
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
func main() {
key, err := generateTunnelKey()
if err != nil {
panic(err)
}
clientCfg := ClientConfig{
SocksHost: "127.0.0.1",
SocksPort: 1080,
GoogleHost: "216.239.38.120",
SNI: "www.google.com",
ScriptKeys: []string{os.Getenv("APPS_SCRIPT_DEPLOYMENT_ID")},
TunnelKey: key,
}
serverCfg := ServerConfig{
ServerHost: "0.0.0.0",
ServerPort: 8443,
TunnelKey: key,
}
clientJSON, _ := json.MarshalIndent(clientCfg, "", " ")
serverJSON, _ := json.MarshalIndent(serverCfg, "", " ")
os.WriteFile("client_config.json", clientJSON, 0600)
os.WriteFile("server_config.json", serverJSON, 0600)
fmt.Printf("Generated key: %s\n", key)
fmt.Println("Configs written to client_config.json and server_config.json")
}Health Check Script (Bash)
健康检查脚本(Bash)
bash
#!/usr/bin/env bashbash
#!/usr/bin/env bashcheck-relay.sh — verify VPS endpoint is reachable before starting client
check-relay.sh — verify VPS endpoint is reachable before starting client
VPS_IP="${GOOSE_VPS_IP:?Set GOOSE_VPS_IP env var}"
VPS_PORT="${GOOSE_VPS_PORT:-8443}"
echo "Checking VPS health endpoint..."
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}"
--connect-timeout 5
"http://${VPS_IP}:${VPS_PORT}/healthz")
--connect-timeout 5
"http://${VPS_IP}:${VPS_PORT}/healthz")
if [ "$HTTP_STATUS" = "200" ]; then
echo "✓ VPS is reachable (HTTP $HTTP_STATUS)"
exit 0
else
echo "✗ VPS health check failed (HTTP $HTTP_STATUS)"
echo " Check: ufw, cloud firewall, server process running?"
exit 1
fi
undefinedVPS_IP="${GOOSE_VPS_IP:?Set GOOSE_VPS_IP env var}"
VPS_PORT="${GOOSE_VPS_PORT:-8443}"
echo "Checking VPS health endpoint..."
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}"
--connect-timeout 5
"http://${VPS_IP}:${VPS_PORT}/healthz")
--connect-timeout 5
"http://${VPS_IP}:${VPS_PORT}/healthz")
if [ "$HTTP_STATUS" = "200" ]; then
echo "✓ VPS is reachable (HTTP $HTTP_STATUS)"
exit 0
else
echo "✗ VPS health check failed (HTTP $HTTP_STATUS)"
echo " Check: ufw, cloud firewall, server process running?"
exit 1
fi
undefinedSOCKS5 Proxy Test (Go)
SOCKS5代理测试(Go)
go
package main
import (
"fmt"
"io"
"net"
"net/http"
"os"
"golang.org/x/net/proxy"
)
func main() {
// Test the GooseRelayVPN SOCKS5 proxy
socksAddr := "127.0.0.1:1080"
dialer, err := proxy.SOCKS5("tcp", socksAddr, nil, proxy.Direct)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create SOCKS5 dialer: %v\n", err)
os.Exit(1)
}
transport := &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
return dialer.Dial(network, addr)
},
}
client := &http.Client{Transport: transport}
resp, err := client.Get("https://api.ipify.org?format=json")
if err != nil {
fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Exit IP (should be your VPS IP): %s\n", body)
}go
package main
import (
"fmt"
"io"
"net"
"net/http"
"os"
"golang.org/x/net/proxy"
)
func main() {
// Test the GooseRelayVPN SOCKS5 proxy
socksAddr := "127.0.0.1:1080"
dialer, err := proxy.SOCKS5("tcp", socksAddr, nil, proxy.Direct)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create SOCKS5 dialer: %v\n", err)
os.Exit(1)
}
transport := &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
return dialer.Dial(network, addr)
},
}
client := &http.Client{Transport: transport}
resp, err := client.Get("https://api.ipify.org?format=json")
if err != nil {
fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Exit IP (should be your VPS IP): %s\n", body)
}Docker Compose for VPS Deployment
Docker Compose部署VPS
yaml
undefinedyaml
undefineddocker-compose.yml — run goose-server on VPS
docker-compose.yml — run goose-server on VPS
version: '3.8'
services:
goose-server:
image: golang:1.22-alpine
working_dir: /app
volumes:
- ./GooseRelayVPN:/app
- ./server_config.json:/app/server_config.json:ro
command: >
sh -c "go build -o /tmp/goose-server ./cmd/server &&
/tmp/goose-server -config /app/server_config.json"
ports:
- "8443:8443"
restart: always
environment:
- CGO_ENABLED=0
---version: '3.8'
services:
goose-server:
image: golang:1.22-alpine
working_dir: /app
volumes:
- ./GooseRelayVPN:/app
- ./server_config.json:/app/server_config.json:ro
command: >
sh -c "go build -o /tmp/goose-server ./cmd/server &&
/tmp/goose-server -config /app/server_config.json"
ports:
- "8443:8443"
restart: always
environment:
- CGO_ENABLED=0
---Browser Configuration
浏览器配置
Firefox
Firefox
- Settings → Network Settings → Manual proxy configuration
- SOCKS Host: , Port:
127.0.0.11080 - Select SOCKS v5
- ✅ Check Proxy DNS when using SOCKS v5 (prevents DNS leaks)
- 设置 → 网络设置 → 手动配置代理
- SOCKS主机:,端口:
127.0.0.11080 - 选择SOCKS v5
- ✅ 勾选使用SOCKS v5时代理DNS(防止DNS泄漏)
Chrome/Edge
Chrome/Edge
Use FoxyProxy or SwitchyOmega:
- Protocol: SOCKS5
- Server:
127.0.0.1 - Port:
1080
- 协议:SOCKS5
- 服务器:
127.0.0.1 - 端口:
1080
System-wide (macOS)
系统级配置(macOS)
System Preferences → Network → Advanced → Proxies → SOCKS Proxy:
127.0.0.1:1080系统偏好设置 → 网络 → 高级 → 代理 → SOCKS代理:
127.0.0.1:1080curl / wget
curl / wget
bash
curl --socks5-hostname 127.0.0.1:1080 https://api.ipify.org
wget -e "use_proxy=yes" -e "http_proxy=socks5h://127.0.0.1:1080" https://api.ipify.orgbash
curl --socks5-hostname 127.0.0.1:1080 https://api.ipify.org
wget -e "use_proxy=yes" -e "http_proxy=socks5h://127.0.0.1:1080" https://api.ipify.orgSSH through tunnel
通过隧道SSH
bash
ssh -o ProxyCommand="nc -X 5 -x 127.0.0.1:1080 %h %p" user@remote-hostbash
ssh -o ProxyCommand="nc -X 5 -x 127.0.0.1:1080 %h %p" user@remote-hostLAN Sharing
局域网共享
To allow other devices on your local network to use the tunnel:
json
{
"socks_host": "0.0.0.0",
"socks_port": 1080,
...
}Other devices connect to as their SOCKS5 proxy.
YOUR_LOCAL_IP:1080⚠️ Only do this on trusted networks — any LAN device can consume your Apps Script quota.
要允许本地网络中的其他设备使用该隧道:
json
{
"socks_host": "0.0.0.0",
"socks_port": 1080,
...
}其他设备连接到作为SOCKS5代理。
YOUR_LOCAL_IP:1080⚠️ 仅在可信网络中执行此操作——局域网内任何设备都可能消耗你的Apps Script配额。
Troubleshooting
故障排除
Pre-flight check fails at startup
启动时预检查失败
The client runs automatic checks. Match error message to cause:
| Error | Likely Cause | Fix |
|---|---|---|
| Apps Script unreachable | Check deployment ID, redeploy script |
| | Copy exact same key to both configs |
Connection refused on | Port 8443 blocked | |
| Forgot to paste deployment ID | Deploy Apps Script → copy Deployment ID |
客户端会自动运行检查。根据错误信息匹配原因:
| 错误 | 可能原因 | 修复方法 |
|---|---|---|
| Apps Script无法访问 | 检查部署ID,重新部署脚本 |
| 客户端和服务器的 | 将相同的密钥复制到两个配置文件中 |
| 8443端口被阻塞 | |
| 忘记粘贴部署ID | 部署Apps Script → 复制部署ID |
Apps Script quota exhausted
Apps Script配额耗尽
Symptom: tunnel stops working, resets ~10:30 AM Iran time (GMT+3:30)
Fix: Add more deployment IDs to script_keys arrayEach deployment: ~20,000 calls/day. Client polls ~1/second idle.
症状:隧道停止工作,约伊朗时间上午10:30(GMT+3:30)重置
修复方法:向script_keys数组添加更多部署ID每个部署每天约可处理20,000次调用。客户端空闲时每秒轮询约1次。
Server not receiving traffic
服务器未收到流量
bash
undefinedbash
undefinedOn VPS: verify server is listening
在VPS上:验证服务器是否在监听
ss -tlnp | grep 8443
ss -tlnp | grep 8443
Test healthz endpoint locally on VPS
在VPS本地测试healthz端点
curl localhost:8443/healthz
curl localhost:8443/healthz
Test from external (your machine)
从外部(你的机器)测试
curl http://YOUR_VPS_IP:8443/healthz
curl http://YOUR_VPS_IP:8443/healthz
Check firewall
检查防火墙
sudo ufw status
undefinedsudo ufw status
undefinedApps Script returning errors
Apps Script返回错误
- Verify in
VPS_URLuses correct VPS IP and port 8443Code.gs - Verify Apps Script is deployed as Web app with Anyone access
- After any code edit, create a New deployment — don't reuse old deployment ID
- Check Apps Script execution log: script.google.com → Executions tab
- 验证中的
Code.gs使用了正确的VPS IP和8443端口VPS_URL - 验证Apps Script部署为Web应用且访问权限为任何人
- 任何代码编辑后,创建新部署——不要重用旧部署ID
- 检查Apps Script执行日志:script.google.com → 执行标签页
Key mismatch debugging
密钥不匹配调试
bash
undefinedbash
undefinedVerify key lengths match (should both be 64 chars)
验证密钥长度是否一致(都应为64位)
cat client_config.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d['tunnel_key']), d['tunnel_key'][:8]+'...')"
cat server_config.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d['tunnel_key']), d['tunnel_key'][:8]+'...')"
undefinedcat client_config.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d['tunnel_key']), d['tunnel_key'][:8]+'...')"
cat server_config.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d['tunnel_key']), d['tunnel_key'][:8]+'...')"
undefinedsystemd service won't start
systemd服务无法启动
bash
sudo systemctl status goose-relay --no-pager
journalctl -u goose-relay -n 50 --no-pagerbash
sudo systemctl status goose-relay --no-pager
journalctl -u goose-relay -n 50 --no-pagerCommon fix: wrong binary path in ExecStart
常见修复方法:ExecStart中的二进制路径错误
which goose-server # find actual path
undefinedwhich goose-server # 查找实际路径
undefinedDNS leaks
DNS泄漏
Ensure browser uses proxy DNS (Firefox: "Proxy DNS when using SOCKS v5"). Without this, DNS queries bypass the tunnel.
确保浏览器使用代理DNS(Firefox:“使用SOCKS v5时代理DNS”)。否则,DNS查询将绕过隧道。
Security Notes
安全注意事项
- Never share — anyone with it can use your VPS as an exit node
tunnel_key - Store configs with restricted permissions:
chmod 600 client_config.json server_config.json - Google never sees plaintext — AES key never touches Apps Script
- The topic in the repo refers to traffic inspection capability; no local MITM cert is needed for this project (unlike
mitm)MasterHttpRelayVPN - Quota resets daily; rotate deployment IDs periodically if quota is a concern
- 切勿共享——任何人拥有该密钥都可以将你的VPS用作出口节点
tunnel_key - 以受限权限存储配置文件:
chmod 600 client_config.json server_config.json - Google不会看到明文——AES密钥永远不会接触Apps Script
- 仓库中的主题指流量检查能力;本项目不需要本地MITM证书(与
mitm不同)MasterHttpRelayVPN - 配额每天重置;如果配额是问题,定期轮换部署ID
Common Patterns
常见模式
Environment-based config generation
基于环境变量的配置生成
bash
undefinedbash
undefinedGenerate config from environment variables
从环境变量生成配置
cat > client_config.json << EOF
{
"socks_host": "127.0.0.1",
"socks_port": 1080,
"google_host": "216.239.38.120",
"sni": "www.google.com",
"script_keys": ["${APPS_SCRIPT_DEPLOYMENT_ID}"],
"tunnel_key": "${GOOSE_TUNNEL_KEY}"
}
EOF
cat > server_config.json << EOF
{
"server_host": "0.0.0.0",
"server_port": 8443,
"tunnel_key": "${GOOSE_TUNNEL_KEY}"
}
EOF
undefinedcat > client_config.json << EOF
{
"socks_host": "127.0.0.1",
"socks_port": 1080,
"google_host": "216.239.38.120",
"sni": "www.google.com",
"script_keys": ["${APPS_SCRIPT_DEPLOYMENT_ID}"],
"tunnel_key": "${GOOSE_TUNNEL_KEY}"
}
EOF
cat > server_config.json << EOF
{
"server_host": "0.0.0.0",
"server_port": 8443,
"tunnel_key": "${GOOSE_TUNNEL_KEY}"
}
EOF
undefinedMultiple Google accounts for maximum capacity
多Google账号实现最大容量
json
{
"script_keys": [
"AKfycbx_account1_deployment1",
"AKfycbx_account1_deployment2",
"AKfycbx_account2_deployment1",
"AKfycbx_account2_deployment2"
]
}Deploy under different Google accounts for independent quotas. All point to the same VPS.
Code.gsjson
{
"script_keys": [
"AKfycbx_account1_deployment1",
"AKfycbx_account1_deployment2",
"AKfycbx_account2_deployment1",
"AKfycbx_account2_deployment2"
]
}在不同的Google账号下部署以获取独立配额。所有部署都指向同一个VPS。
Code.gsVerify exit IP after setup
设置后验证出口IP
bash
undefinedbash
undefinedShould show your VPS IP, not your real IP
应显示你的VPS IP,而非真实IP
curl --socks5-hostname 127.0.0.1:1080 https://api.ipify.org
undefinedcurl --socks5-hostname 127.0.0.1:1080 https://api.ipify.org
undefined