SOCKS5 VPN that tunnels raw TCP through Google Apps Script to a VPS exit server, with end-to-end AES-256-GCM and domain-fronted TLS to Google
SOCKS5 VPN that tunnels raw TCP through Google Apps Script to a VPS exit server, with end-to-end AES-256-GCM and domain-fronted TLS to Google
A SOCKS5 VPN that tunnels raw TCP through a Google Apps Script web app to your own small VPS exit server. To anything on the network path your client only ever talks TLS to a Google IP with SNI=www.google.com. Everything in flight is AES-256-GCM encrypted end-to-end — Google never sees plaintext and never holds the key.
Table of Contents⚠️ You need a small VPS for the exit server. Unlike pure-Apps-Script proxies, this project tunnels raw TCP — anything SOCKS5 can carry — so a real
net.Dialhas to happen somewhere. A small $4/month VPS is plenty. In exchange you can tunnel SSH, IMAP, custom protocols, anything — not just HTTP.
Browser/App
-> SOCKS5 (127.0.0.1:1080)
-> Zstd-compressed + AES-256-GCM frame batches
-> HTTPS to a Google edge IP (SNI=www.google.com, Host=script.google.com)
-> Apps Script doPost() (dumb forwarder, never sees plaintext)
-> Your VPS :8443/tunnel (decrypts, demuxes by session_id, dials target)
<- Same path in reverse via long-polling
Your application sends TCP bytes through the SOCKS5 listener on your computer. The client groups them into batches of frames, Zstandard-compresses each batch (for compressible traffic such as plain HTTP or JSON APIs this reduces the body size by up to 65%, keeping you further from Apps Script's daily quota limits), then seals the whole batch under a single AES-256-GCM envelope and POSTs it over a domain-fronted HTTPS connection to your Apps Script web app. The Apps Script is a ~30-line script that forwards the body verbatim to your VPS — it never decrypts and the AES key never touches Google. Your VPS decrypts, dials the real target, and pumps bytes back along the same path. The filter sees only TLS to Google.
Apps Script daily quota. Each Google account has a UrlFetch quota of about 20,000 executions per day on the free tier — shared across every deployment under that account, not per deployment. The quota resets at midnight Pacific (≈10:30 AM Iran time in summer, ≈11:30 AM in winter). The Zstd compression above is what stretches that quota the furthest.
You need a VPS with a public IP. Linux or Windows Server — any provider works.
You need two separate programs:
goose-client — runs on your own computer. This is what you run every day.goose-server — runs on your VPS. You set it up once and leave it running.Linux VPS shortcut: If your exit server is Linux and you have root, the installer script below bundles Steps 2–7 for the server (download, config, tunnel key, systemd unit, firewall) into one command. You still need to set up the client and Apps Script (Steps 5 and 8+) on your own machine.
bash <(curl -Ls https://raw.githubusercontent.com/Kianmhz/GooseRelayVPN/main/scripts/goose-server.sh)The script verifies the release tarball against its published
SHA256SUMS.txtbefore installing, generates a freshtunnel_keyyou'll paste into the client config, and exposesinstall/update/uninstall/ reconfigure menus on re-run.
Option A — Download a pre-built release (recommended):
Go to the Releases page.
Download the right archive for your OS:
GooseRelayVPN-client-vX.Y.Z-windows-amd64.zipGooseRelayVPN-client-vX.Y.Z-darwin-amd64.tar.gzGooseRelayVPN-client-vX.Y.Z-darwin-arm64.tar.gzGooseRelayVPN-client-vX.Y.Z-linux-amd64.tar.gzGooseRelayVPN-client-vX.Y.Z-android-arm64.tar.gzFor the server, SSH into your VPS and download the binary for your server OS:
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
GooseRelayVPN-server-vX.Y.Z-windows-amd64.zip from the Releases page and extract it to a folder such as C:\goose-relay\. See the Windows Server (NSSM) subsection of Step 8 below for service setup.(Replace vX.Y.Z with the latest version number from the Releases page.)
If the Releases page doesn't open, you can download directly using these links (replace
vX.Y.Zwith the latest version):
- Client — Windows:
https://github.com/Kianmhz/GooseRelayVPN/releases/download/vX.Y.Z/GooseRelayVPN-client-vX.Y.Z-windows-amd64.zip- Client — macOS (Apple Silicon):
https://github.com/Kianmhz/GooseRelayVPN/releases/download/vX.Y.Z/GooseRelayVPN-client-vX.Y.Z-darwin-arm64.tar.gz- Client — macOS (Intel):
https://github.com/Kianmhz/GooseRelayVPN/releases/download/vX.Y.Z/GooseRelayVPN-client-vX.Y.Z-darwin-amd64.tar.gz- Client — Linux:
https://github.com/Kianmhz/GooseRelayVPN/releases/download/vX.Y.Z/GooseRelayVPN-client-vX.Y.Z-linux-amd64.tar.gz- Client — Android/Termux:
https://github.com/Kianmhz/GooseRelayVPN/releases/download/vX.Y.Z/GooseRelayVPN-client-vX.Y.Z-android-arm64.tar.gz- Server — Linux:
https://github.com/Kianmhz/GooseRelayVPN/releases/download/vX.Y.Z/GooseRelayVPN-server-vX.Y.Z-linux-amd64.tar.gz
Option B — Build from source (Go 1.22+) — not recommended, may be unstable:
git clone https://github.com/kianmhz/GooseRelayVPN.git
cd GooseRelayVPN
go build -o goose-client ./cmd/client
go build -o goose-server ./cmd/server
Option C — Run only the server with Docker (GHCR):
If you prefer containers on your VPS, you can run goose-server directly from GHCR:
docker pull ghcr.io/kianmhz/gooserelayvpn-server:latest
Run this once:
openssl rand -hex 32
Copy the 64-character string it prints. You'll use the same value in both the client and server configs. Keep it secret — anyone with this key can use your tunnel.
Copy the example configs:
cp client_config.example.json client_config.json
cp server_config.example.json server_config.json
Open both files and paste your key into the tunnel_key field. Leave script_keys empty for now.
client_config.json:
{
"socks_host": "127.0.0.1",
"socks_port": 1080,
"google_host": "216.239.38.120",
"sni": "www.google.com",
"script_keys": ["PASTE_DEPLOYMENT_ID"],
"tunnel_key": "PASTE_OUTPUT_OF_GEN_KEY"
}
server_config.json:
{
"server_host": "0.0.0.0",
"server_port": 8443,
"tunnel_key": "SAME_VALUE_AS_CLIENT"
}
This is the free Google-side piece that hides your traffic.
apps_script/Code.gs.const RELAY_URLS = [
'http://YOUR.VPS.IP:8443/tunnel',
];
RELAY_URLS is an array so you can list multiple VPS exit servers — Code.gs tries them in order and only falls over to the next one on an error. For a single VPS, one entry is enough.script_keys.script_keys in client_config.json.⚠️ Every time you edit
Code.gsyou must create a new deployment (Deploy → New deployment) and updatescript_keys. Just saving the code is not enough.
The server needs port 8443 to be reachable from the internet. On your VPS run:
sudo ufw allow 8443/tcp
Then verify it works from your own computer (replace with your real VPS IP):
curl http://YOUR.VPS.IP:8443/healthz
You should get JSON like { "ok": true, "version": "vX.Y.Z", "protocol": 1 } with HTTP 200. If curl times out or refuses, also check your cloud provider's firewall (called "Security Groups" on AWS/Hetzner, "Firewall Rules" on DigitalOcean/Vultr, etc.) and add an inbound rule for TCP port 8443.
On your VPS, run the server binary:
Linux:
./goose-server -config server_config.json
Windows Server:
.\goose-server.exe -config server_config.json
You should see it print the listening address and the healthz/tunnel URLs. Leave this terminal open, or set up the systemd/NSSM service (Step 8) to keep it running after reboots.
Docker (GHCR image):
⚠️ Important: The container does not auto-generate
server_config.json. You must create and editserver_config.jsonfirst (with your owntunnel_key), then start the container.
docker run -d \
--name goose-server \
--restart unless-stopped \
-p 8443:8443 \
-v $(pwd)/server_config.json:/app/server_config.json:ro \
ghcr.io/kianmhz/gooserelayvpn-server:latest
Docker Compose (recommended for container setup):
cp server_config.example.json server_config.json
nano server_config.json
docker compose up -d
The repo includes docker-compose.yml. By default it uses ghcr.io/kianmhz/gooserelayvpn-server:latest, and you can override it with:
GOOSE_SERVER_IMAGE=ghcr.io/kianmhz/gooserelayvpn-server:vX.Y.Z docker compose up -d
Verify from your own computer:
curl http://YOUR.VPS.IP:8443/healthz
If you want the exit server to start automatically after a VPS reboot, set up a service for your VPS OS.
Run on your VPS:
sudo nano /etc/systemd/system/goose-relay.service
Paste this (adjust the path if your binary is in a different location):
[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.target
Then run:
sudo systemctl daemon-reload
sudo systemctl enable goose-relay
sudo systemctl start goose-relay
sudo systemctl status goose-relay --no-pager
Use NSSM (Non-Sucking Service Manager) to register goose-server as a Windows service. The goose-server.exe binary is a plain Go binary — no installer needed.
1. Open port 8443 in Windows Firewall (run as Administrator in Command Prompt):
netsh advfirewall firewall add rule name="GooseRelayVPN" protocol=TCP dir=in localport=8443 action=allow
Also add an inbound TCP/8443 rule in your cloud provider's firewall panel (Security Groups / Firewall Rules).
2. Download NSSM from https://nssm.cc/download, extract it, and note the path to nssm.exe (e.g. C:\nssm\win64\nssm.exe).
3. Register and start the service (run as Administrator):
No open issues yet, or sync has not completed.