A global proxy app for Android, modernised around a VPN-first architecture.
ProxyDroid forwards device traffic to an upstream SOCKS5 or HTTP proxy without requiring root. It installs a VpnService, captures IP packets on a TUN device, and converts TCP/UDP flows into proxy connections in userspace.
- VPN-first. No iptables, no redsocks, no root. The app runs as a standard Android
VpnService, which works on every supported Android release. - Rust tun2socks. The packet-to-socket bridge lives in
app/src/main/rust/proxydroid-tun2socks, built with netstack-smoltcp and invoked from Kotlin through JNI. Cargo builds are wired in viaorg.mozilla.rust-android-gradle. - Compose UI. The settings and status surfaces are written in Jetpack Compose with Material 3.
- Per-app bypass. Apps can be excluded from the tunnel via the standard
VpnServiceaddDisallowedApplicationAPI.
- SOCKS5 (with optional username/password auth)
- HTTP
CONNECT(with optional Basic auth)
- JDK 17 (Gradle 8.x does not accept JDK 21+)
- Android SDK with
compileSdk36 installed - Android NDK
25.1.8937393 - CMake
3.22.1 - Rust stable toolchain with the Android targets:
aarch64-linux-android,armv7-linux-androideabi,i686-linux-android,x86_64-linux-android
AGP is pinned to 8.1.2 and Kotlin to 1.9.10. See
gradle/libs.versions.tomlfor every version. Do not bump AGP without verifying therust-android-gradle0.9.6mergeJniLibFoldersduplicate-resources interaction (cf. commits0249f91,8875c74).
- Open the project root.
- Let Gradle sync β Cargo runs as part of
cargoBuildand feeds the JNI libraries into the merged APK. Build > Make Project.
./gradlew assembleDebug # debug APK at app/build/outputs/apk/debug/ ./gradlew assembleRelease # release APK; requires signing config (see below)
Signing for release is opt-in. Add a local.properties with:
KEYSTORE_PATH=/absolute/path/to/keystore.jks KEYSTORE_PASSWORD=... KEY_ALIAS=... KEY_PASSWORD=...
If those keys are absent the release variant builds unsigned.
app/ βββ src/main/ β βββ java/org/proxydroid/ # Kotlin sources (Compose UI + VpnService) β βββ res/ # Resources β βββ cpp/ # Native helpers built via CMake β β βββ exec/ # termExec β JNI native-process helper β βββ rust/ β β βββ proxydroid-tun2socks/ # Rust tun2socks crate (netstack-smoltcp) β βββ AndroidManifest.xml βββ build.gradle # App module build (consumes libs.versions.toml) βββ proguard-rules.pro gradle/ βββ libs.versions.toml # Single source of truth for dependency versions βββ wrapper/ build.gradle # Root build, repos + plugin classpath gradle.properties # JVM args + AGP compileSdk suppression settings.gradle scripts/ # Test helpers (Python SOCKS5/HTTP servers, etc.)
Legacy
cpp/libeventandcpp/redsocksdirectories from the iptables era are scheduled for removal in the ongoing refactor. The redsocks path is no longer reachable from Kotlin.
HostSocks5ProxyIntegrationTest runs inside an Android emulator and routes an HTTP request through a SOCKS5 proxy listening on the host. The host proxy is a small stdlib-only Python server in scripts/socks5_test_server.py.
The emulator reaches the host loopback via the alias 10.0.2.2, so a host proxy bound to 0.0.0.0:1080 is seen by the device as 10.0.2.2:1080.
# Terminal 1 β start the SOCKS5 proxy on the host: python3 scripts/socks5_test_server.py --host 0.0.0.0 --port 1080 # Terminal 2 β boot any AVD, then run the instrumentation test: ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=org.proxydroid.HostSocks5ProxyIntegrationTest
Override defaults with -Pandroid.testInstrumentationRunnerArguments.socksHost=..., socksPort, targetHost, targetPort.
armeabi-v7a, arm64-v8a, x86, x86_64.
minSdk24 (Android 7.0)targetSdk/compileSdk36 (Android 16) β required by Google Play 2025/2026 policy
GPLv3.


























