
gooserelayvpn-android-client
Android VPN client that tunnels SOCKS5 traffic through Google Apps Script to a VPS exit server with AES-256-GCM encryption and domain fronting
- Installs
- 213
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/reason-machines/devtools-skills --skill gooserelayvpn-android-client- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads gooserelayvpn-android-client automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
GooseRelayVPN Android Client Skill
Skill by ara.so — Devtools Skills collection.
Overview
GooseRelayVPN Android Client is an Android application that provides a VPN service tunneling TCP traffic through Google Apps Script to a VPS exit server. It uses:
- Local SOCKS5 proxy for app/browser traffic
- AES-256-GCM encryption for tunnel security
- Domain fronting via Google infrastructure (Apps Script)
- Android VpnService integration with tun2socks
- Profile-based configuration with JSON import/export
Architecture flow:
- Android app traffic → SOCKS5 (127.0.0.1:1080)
- GooseRelay core encrypts with AES key
- HTTPS transport through Google Apps Script deployment
- VPS exit server decrypts and forwards to target
Prerequisites
Before using the Android client, you must set up upstream infrastructure:
- VPS server running
goose-server(from main GooseRelayVPN project) - Google Apps Script deployment with
apps_script/Code.gs - Tunnel encryption key generated via
scripts/gen-key.sh - Deployment ID(s) from Apps Script
Upstream project: https://github.com/kianmhz/GooseRelayVPN
Building the Android Client
Requirements
- Android Studio
- JDK 17
- Go 1.22+
- Android SDK with NDK
gomobiletool
Build Go Mobile AAR
The core GooseRelay logic is compiled to an Android AAR library:
# From project root
bash android/build_go_mobile.sh
This script:
- Installs
gomobileif needed - Compiles Go code to AAR for arm64-v8a, armeabi-v7a, x86, x86_64
- Outputs to
android/app/libs/gooserelay.aar
Manual AAR build:
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
gomobile bind \
-target=android \
-androidapi=21 \
-o android/app/libs/gooserelay.aar \
-v \
./mobile
Build Debug APK
cd android
./gradlew :app:assembleDebug
# Output: android/app/build/outputs/apk/debug/app-debug.apk
Build Release APK
cd android
./gradlew :app:assembleRelease
# Requires signing configuration in android/app/build.gradle
Profile Configuration
Profile JSON Structure
{
"debug_timing": false,
"socks_host": "127.0.0.1",
"socks_port": 1080,
"google_host": "216.239.38.120",
"sni": [
"www.google.com",
"mail.google.com",
"accounts.google.com"
],
"script_keys": [
"DEPLOYMENT_ID_FROM_APPS_SCRIPT",
"OPTIONAL_SECOND_DEPLOYMENT_ID"
],
"tunnel_key": "BASE64_ENCODED_AES_KEY_FROM_GEN_KEY_SCRIPT"
}
Field Descriptions
| Field | Type | Description |
|---|---|---|
debug_timing | bool | Enable timing debug logs |
socks_host | string | Local SOCKS5 bind address (usually 127.0.0.1) |
socks_port | int | Local SOCKS5 port (default 1080) |
google_host | string | Google IP for domain fronting (216.239.38.120 is common) |
sni | []string | SNI hostnames for TLS handshake rotation |
script_keys | []string | Apps Script deployment IDs (one or more for redundancy) |
tunnel_key | string | Base64 AES-256 key (must match server-side key) |
Generating Tunnel Key
Use the upstream script to generate a secure key:
# From GooseRelayVPN main repo
bash scripts/gen-key.sh
# Outputs base64-encoded key
# Example: a3d7f9e2b1c4...
Important: The same tunnel_key must be used on both the Android client and the VPS goose-server.
In-App Profile Management
Create new profile:
- Open app → Profiles tab
- Tap "+" button
- Enter profile name and configuration
- Save
Import profile from JSON:
- Profiles tab → menu → Import
- Select JSON file from storage
- Profile is added to list
Export profile to JSON:
- Profiles tab → long-press profile
- Select Export
- JSON saved to Downloads
Android VPN Service Integration
VpnService Implementation
The app uses Android's VpnService API to capture device traffic:
// Simplified example from Android codebase
class GooseVpnService : VpnService() {
private val socksHost = "127.0.0.1"
private val socksPort = 1080
fun startVpn(profile: Profile) {
// 1. Start GooseRelay core (via JNI to Go AAR)
GooseRelay.start(profile.toJson())
// 2. Configure VPN interface
val builder = Builder()
.setSession("GooseRelayVPN")
.addAddress("10.0.0.2", 24)
.addRoute("0.0.0.0", 0)
.addDnsServer("8.8.8.8")
// 3. Exclude apps if split tunneling enabled
if (profile.splitTunnel) {
profile.allowedApps.forEach { pkg ->
builder.addAllowedApplication(pkg)
}
}
val vpnInterface = builder.establish()
// 4. Start tun2socks to forward traffic to SOCKS5
Tun2Socks.start(
vpnInterface.fd,
socksHost,
socksPort
)
}
}
Permissions Required
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application>
<service
android:name=".service.GooseVpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
</application>
</manifest>
Go Mobile Bridge
The Go core is exposed to Android via gomobile:
Mobile Package Interface
mobile/mobile.go:
package mobile
import (
"encoding/json"
"github.com/Hidden-Node/GooseRelayVPN/client"
)
// Config matches Android profile JSON structure
type Config struct {
DebugTiming bool `json:"debug_timing"`
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"`
}
var relayClient *client.Client
// Start initializes and starts the GooseRelay client
func Start(configJSON string) error {
var cfg Config
if err := json.Unmarshal([]byte(configJSON), &cfg); err != nil {
return err
}
relayClient = client.NewClient(client.Config{
DebugTiming: cfg.DebugTiming,
SocksAddr: fmt.Sprintf("%s:%d", cfg.SocksHost, cfg.SocksPort),
GoogleHost: cfg.GoogleHost,
SNI: cfg.SNI,
ScriptKeys: cfg.ScriptKeys,
TunnelKey: cfg.TunnelKey,
})
return relayClient.Start()
}
// Stop gracefully stops the relay client
func Stop() error {
if relayClient != nil {
return relayClient.Stop()
}
return nil
}
// GetStats returns JSON statistics
func GetStats() string {
if relayClient == nil {
return "{}"
}
stats := relayClient.GetStats()
data, _ := json.Marshal(stats)
return string(data)
}
Calling from Android (Kotlin)
import gooserelay.Gooserelay // Generated from AAR
class RelayManager {
fun startRelay(profile: Profile) {
val configJson = profile.toJson()
try {
Gooserelay.start(configJson)
Log.i("GooseRelay", "Started successfully")
} catch (e: Exception) {
Log.e("GooseRelay", "Start failed: ${e.message}")
}
}
fun stopRelay() {
try {
Gooserelay.stop()
} catch (e: Exception) {
Log.e("GooseRelay", "Stop failed: ${e.message}")
}
}
fun getStats(): Stats? {
return try {
val json = Gooserelay.getStats()
Json.decodeFromString<Stats>(json)
} catch (e: Exception) {
null
}
}
}
Common Usage Patterns
Full Device VPN
Route all device traffic through the tunnel:
// In profile configuration
val profile = Profile(
name = "Full VPN",
socksPort = 1080,
scriptKeys = listOf(System.getenv("APPS_SCRIPT_DEPLOYMENT_ID")),
tunnelKey = System.getenv("GOOSE_TUNNEL_KEY"),
splitTunnel = false, // All apps
excludeLocalNetwork = true
)
vpnService.startVpn(profile)
Split Tunneling
Route only specific apps through the tunnel:
val profile = Profile(
name = "Split Tunnel",
socksPort = 1080,
scriptKeys = listOf(System.getenv("APPS_SCRIPT_DEPLOYMENT_ID")),
tunnelKey = System.getenv("GOOSE_TUNNEL_KEY"),
splitTunnel = true,
allowedApps = listOf(
"com.android.chrome",
"org.telegram.messenger"
)
)
vpnService.startVpn(profile)
Manual SOCKS5 Proxy
Use without VpnService (manual app configuration):
// Start only the SOCKS5 server, no VPN
fun startSocksOnly(profile: Profile) {
GooseRelay.start(profile.toJson())
// Apps must be configured to use 127.0.0.1:1080 as SOCKS5 proxy
}
Logging and Telemetry
Real-time Logs
The app provides a Logs tab showing Android and Go core logs:
// Android side logger forwarding to UI
object LogCollector {
private val logs = mutableListOf<LogEntry>()
fun addLog(level: String, tag: String, message: String) {
logs.add(LogEntry(
timestamp = System.currentTimeMillis(),
level = level,
tag = tag,
message = message
))
// Notify UI observers
notifyLogListeners()
}
}
// Go side: logs are captured via custom writer
Telemetry Stats
Real-time connection statistics:
data class TelemetryStats(
val bytesUploaded: Long,
val bytesDownloaded: Long,
val activeConnections: Int,
val successRate: Float,
val avgLatency: Long
)
fun updateTelemetry() {
val statsJson = Gooserelay.getStats()
val stats = Json.decodeFromString<TelemetryStats>(statsJson)
// Update UI cards
uploadCard.text = formatBytes(stats.bytesUploaded)
downloadCard.text = formatBytes(stats.bytesDownloaded)
latencyCard.text = "${stats.avgLatency}ms"
}
CI/CD and Release
GitHub Actions Workflows
Debug CI (.github/workflows/android-ci.yml):
name: Android CI
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.22'
- name: Build Go Mobile AAR
run: bash android/build_go_mobile.sh
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Build Debug APK
run: |
cd android
./gradlew assembleDebug
- name: Upload APK
uses: actions/upload-artifact@v3
with:
name: app-debug
path: android/app/build/outputs/apk/debug/app-debug.apk
Release Workflow (.github/workflows/release.yml):
name: Release Build
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build AAR
run: bash android/build_go_mobile.sh
- name: Decode Keystore
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > android/keystore.jks
- name: Build Release APK
env:
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
cd android
./gradlew assembleRelease
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: android/app/build/outputs/apk/release/app-release.apk
Required secrets:
ANDROID_KEYSTORE_BASE64: Base64-encoded keystore fileANDROID_KEYSTORE_PASSWORD: Keystore passwordANDROID_KEY_ALIAS: Key alias in keystoreANDROID_KEY_PASSWORD: Key password
Troubleshooting
Connection Stuck in "Preparing" State
Symptoms: VPN shows "Preparing" but never connects.
Causes:
- Invalid
script_keys(deployment IDs) - Mismatched
tunnel_keybetween client and server - Apps Script deployment not accessible
Solution:
# Check logs tab in app for specific errors
# Common log patterns:
# "Failed to connect to script" → Check deployment ID
# "Decryption failed" → Check tunnel_key matches server
# "Connection timeout" → Verify VPS server is running
# Verify server-side key matches:
# On VPS: cat /etc/goose-server/config.json | jq .tunnel_key
# In Android profile: check tunnel_key field
SOCKS Port Busy Error
Symptoms: "bind: address already in use" in logs.
Solution:
// Ensure clean disconnect before reconnect
fun reconnect() {
// Stop VPN service
vpnService.stop()
// Wait for port release
Thread.sleep(2000)
// Check no other app uses port 1080
// Change profile socks_port if needed
profile.socksPort = 1081
vpnService.start()
}
No Traffic Flowing Through VPN
Symptoms: VPN connected but no internet access.
Checklist:
- VPN permission granted
- Split tunnel app selection correct
- DNS servers configured
- Local network excluded if needed
Solution:
// Verify VPN builder configuration
val builder = Builder()
.addAddress("10.0.0.2", 24)
.addRoute("0.0.0.0", 0)
.addDnsServer("8.8.8.8")
.addDnsServer("1.1.1.1")
// Exclude local network
if (profile.excludeLocalNetwork) {
builder.addRoute("0.0.0.0", 5)
builder.addRoute("8.0.0.0", 7)
builder.addRoute("11.0.0.0", 8)
// ... exclude 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
}
val vpnInterface = builder.establish()
Apps Script Deployment Issues
Symptoms: "Script execution failed" in logs.
Solution:
# Verify deployment ID format (should be long alphanumeric string)
# Example: AKfycbzXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Test deployment manually:
curl -L "https://script.google.com/macros/s/DEPLOYMENT_ID/exec?action=ping"
# Ensure Apps Script has correct VPS endpoint in Code.gs:
# const VPS_ENDPOINT = "https://your-vps-ip:8443";
High Latency or Slow Speeds
Symptoms: Connected but slow performance.
Optimization:
{
"debug_timing": false,
"sni": [
"www.google.com"
],
"script_keys": [
"PRIMARY_DEPLOYMENT_ID",
"BACKUP_DEPLOYMENT_ID"
]
}
Tips:
- Use multiple
script_keysfor load balancing - Choose closer Google IP in
google_host - Optimize VPS server configuration
- Enable
debug_timingtemporarily to identify bottlenecks
AAR Build Failures
Symptoms: build_go_mobile.sh fails.
Solution:
# Ensure gomobile is installed
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
# Check Android NDK is installed
# In Android Studio: Tools → SDK Manager → SDK Tools → NDK
# Set environment variables
export ANDROID_HOME=$HOME/Android/Sdk
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/25.1.8937393
# Retry build
bash android/build_go_mobile.sh
Certificate/TLS Errors
Symptoms: "x509: certificate signed by unknown authority"
Solution:
// If using self-signed cert on VPS, Apps Script must trust it
// Better: Use Let's Encrypt on VPS
// In Code.gs, configure:
const ALLOW_SELF_SIGNED = false; // Set true only for testing
Best Practices
- Key Management: Store
tunnel_keyin Android Keystore, not plaintext - Multiple Deployments: Use 2-3
script_keysfor redundancy - Battery Optimization: Exclude VPN service from battery optimization
- Testing: Test with
debug_timing: trueduring setup - Backup Profiles: Export profiles before app updates
- Server Monitoring: Monitor VPS
goose-serverlogs alongside Android logs
Additional Resources
- Main project: https://github.com/kianmhz/GooseRelayVPN
- Apps Script setup: See upstream
apps_script/Code.gs - Server setup: See upstream
server/directory - Issues: Check open issues at https://github.com/Hidden-Node/GooseRelayVPN-AndroidClient/issues
FAQ
What does the gooserelayvpn-android-client skill do?
Android VPN client that tunnels SOCKS5 traffic through Google Apps Script to a VPS exit server with AES-256-GCM encryption and domain fronting
How do I install gooserelayvpn-android-client?
Run npx skills add https://github.com/reason-machines/devtools-skills --skill gooserelayvpn-android-client in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/gooserelayvpn-android-client/ (personal) or .claude/skills/gooserelayvpn-android-client/ (project).
Which AI agents can use gooserelayvpn-android-client?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is gooserelayvpn-android-client safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains gooserelayvpn-android-client?
It is published by reason-machines in reason-machines/devtools-skills. It has 213 recorded installs.
More from reason-machines/devtools-skills
cc-switch-cli
reason-machines/devtools-skills
Cross-platform CLI tool for managing Claude Code, Codex, Gemini, OpenCode & OpenClaw providers, MCP servers, prompts, skills, and proxies.
wx-cli-wechat-local-data
reason-machines/devtools-skills
Open the skill to read its SKILL.md instructions.
chrome-devtools-mcp-automation
reason-machines/devtools-skills
Use Chrome DevTools MCP to control Chrome, debug web apps, analyze performance, and automate browser tasks via MCP tools
officecli-office-automation
reason-machines/devtools-skills
Use OfficeCLI to create, read, and edit Word, Excel, and PowerPoint files from the command line with AI-friendly commands.
cli-anything-agent-native-software
reason-machines/devtools-skills
Generate and use command-line interfaces that make any software controllable by AI agents with structured JSON output
autocli-web-scraping
reason-machines/devtools-skills
Open the skill to read its SKILL.md instructions.
Popular mobile skills
design-mobile-apps
designed-by-ai/skills
Design mobile app screens with Sleek, edit Sleek projects, and implement their designs in React Native or HTML.
ios-design
uizze.sh
Design and review iOS UI/UX for iPhone apps in SwiftUI, UIKit, or React Native. Use for mobile app design, screen redesigns, navigation flows, typography, forms, keyboard and safe-area layout, and accessibility checks. Apply Apple Human Interface Guidelines and consult real product references through the optional Uizze connection.
vercel-react-native-skills
vercel-labs/agent-skills
React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.
animate-expo
emilkowalski/skills
Build animations in React Native and Expo, making the decisions in the order that determines whether they feel right — should it animate, which thread it runs on, which properties, spring or timing, how the gesture hands off, how it degrades. Writes the implementation with Reanimated, Gesture Handler, Expo Router and expo-haptics. Use when animating anything in an Expo app, adding gestures, sheets, screen transitions, press feedback or haptics, or fixing motion that stutters on device. For web animation use animate.
xcode-project-setup
firebase/agent-skills
Safely modifies Xcode projects (.pbxproj) to add Swift Packages and link files. Use this skill whenever an iOS project needs dependencies installed (e.g. Firebase, Alamofire).
firebase-remote-config-basics
firebase/agent-skills
Manages Firebase Remote Config templates, feature flags, loading strategies, and SDKs (Android, iOS). Use when downloading/deploying remoteconfig JSON templates, managing version history/feature flags, setting in-app defaults, fetchAndActivate(), real-time listeners, or SDK setup. Don't use for Firebase Hosting, Auth, Firestore, Data Connect, Crashlytics, or App Hosting.