Concepts
Per-session VPN
How each device gets its own switchable egress location.
Это содержимое пока не доступно на вашем языке.
Every emulator session can route all of the device’s traffic (TCP, UDP and DNS) through a VPN, and the user can switch the location from the session toolbar at any time.
How it works
Section titled “How it works”The session Pod has a vpn sidecar running sing-box
in the Pod’s network namespace, which Android shares:
- sing-box opens a
tuninterface, and the agent adds policy routing inside Android that sends every app’s traffic into it (Android’s own network daemon manages the routing there, so sing-box can’t); - cluster and LAN ranges (
vpn.bypassCIDRs) are excluded, and so is everything running as root (the agent, sing-box itself, Android’s root daemons), so the portal can still reach the agent; - each location is a sing-box outbound, plus
direct, behind a selector; - switching location changes the selector through sing-box’s local API, so the switch is instant and needs no restart;
- the device’s DNS queries are captured from the tunnel and handed to the session’s agent, which logs them, answers your rewrites and resolves the rest through the selected location, so lookups don’t leak (see DNS log and rewrites);
- those lookups return IPv4 addresses only (
AAAAanswers are empty), so the device never tries IPv6 through a location that can’t carry it.
The launch dialog shows a location’s flag when its id or label is a
country code or name. An app listed in a location’s defaultFor starts in
that location. Otherwise the dialog and the quick-launch button use the location you
used last time with that provider, or with Any (remembered in the browser’s localStorage, also when you switch
during a session). If there is none, or it is no longer offered, it falls
back to the configured default (vpn.default). With vpn.direct: false
there is no VPN-less option at all.
The same tunnel carries the session’s network conditions:
latency, bandwidth limits, packet loss and outages applied with tc netem,
and regions with their own round trips to CDN edges and to servers.
Android itself is barely configured (only Private DNS is turned off, so
lookups stay visible to the agent); to apps it looks like a normal
network. Port forwarding (adb reverse, your connected computer)
runs over loopback and is unaffected by the VPN.
Locations are sing-box outbounds
Section titled “Locations are sing-box outbounds”Holtdroid has no code for any particular VPN vendor. A location is an id, a label and a sing-box outbound (or endpoint, such as WireGuard): SOCKS, Shadowsocks, VLESS, Hysteria, WireGuard, anything sing-box speaks. Holtdroid only tags it with the location id and puts it behind the selector.
Every session Pod runs its own copy of these outbounds. That is fine for proxies that accept many connections with the same credentials, but not for WireGuard: VPN services usually give one key per account, and the same key connected from several Pods at once makes the peers knock each other off.
Recommended: a shared VPN gateway
Section titled “Recommended: a shared VPN gateway”Run one sing-box yourself as a VPN gateway. It holds the real VPN
connection, one tunnel per location, and offers a SOCKS server where the
username selects the location. Each Holtdroid location is then just “SOCKS to
the gateway, user de”:
flowchart LR
subgraph s1["Session Pod 1"]
e1["emulator"] --> v1["sing-box sidecar"]
end
subgraph s2["Session Pod 2"]
e2["emulator"] --> v2["sing-box sidecar"]
end
v1 -- "socks, user de" --> gw["VPN gateway<br/>(your sing-box)"]
v2 -- "socks, user nl" --> gw
gw -- "WireGuard" --> de[(VPN server DE)]
gw -- "WireGuard" --> nl[(VPN server NL)]
- One key per location serves any number of sessions.
- Switching stays per session: each sidecar has its own selector.
- Sessions on the same location share its egress IP.
- Adding a vendor or a country is a change to the gateway, not to Holtdroid.
Shared VPN gateway has a complete setup. Configuration keys are on the emulator provider page.