Documentation Index
Fetch the complete documentation index at: https://mintlify.com/SpaceNeuroX/proxy-turn-vk-android/llms.txt
Use this file to discover all available pages before exploring further.
wdtt-server stores all its configuration in a single JSON file: /etc/wdtt/passwords.json. The file is written by the deploy script on first run and updated automatically whenever a password is created, a device connects, or traffic statistics are flushed. You can edit it by hand at any time — send SIGHUP to the process afterward to hot-reload without dropping active sessions.
passwords.json structure
{
"main_password": "YourStrongMainPassword",
"admin_id": "987654321",
"bot_token": "123456:ABC-...",
"passwords": {
"GeneratedPass01": {
"label": "User 1",
"device_ids": ["abc123"],
"max_devices": 1,
"expires_at": 1751000000,
"down_bytes": 104857600,
"up_bytes": 52428800,
"vk_hash": "AbCdEfGhIjKl",
"ports": "56000,56001,9000",
"is_deactivated": false
}
},
"devices": {
"device-uuid-here": {
"device_id": "device-uuid-here",
"ip": "10.66.0.1",
"priv_key": "<base64>",
"pub_key": "<base64>",
"down_bytes": 52428800,
"up_bytes": 26214400
}
}
}
Top-level fields
| Field | Type | Description |
|---|
main_password | string | The owner password. Passed via -password at startup or through the deploy script. |
admin_id | string | Numeric Telegram user ID of the bot admin. |
bot_token | string | Telegram Bot API token. Both fields must be set for the bot to start. |
passwords | object | Map of generated password strings → PasswordEntry objects. |
devices | object | Map of device UUID strings → ClientDevice objects. |
PasswordEntry fields
Each key in passwords is the password string itself. The value is a PasswordEntry object:
| Field | Type | Description |
|---|
label | string | Human-readable name shown in the Telegram bot list. Auto-generated as “Доступ N” if not set. |
device_id | string | Legacy single-device binding field retained for backward compatibility. New connections use device_ids instead. |
device_ids | array of strings | UUIDs of devices that have bound to this password. Populated automatically on first connect. |
max_devices | integer | Maximum number of devices that may bind to this password. 0 or 1 both mean a single device. |
expires_at | integer | Expiry as a Unix timestamp (seconds). 0 means the password never expires. |
down_bytes | integer | Cumulative bytes downloaded by clients using this password (traffic accounting). |
up_bytes | integer | Cumulative bytes uploaded by clients using this password. |
vk_hash | string | VK call hash stored when the password was created via the bot. Used to generate wdtt:// and qwdtt:// connection links. |
ports | string | Port triple in dtls,wg,tun format (e.g. "56000,56001,9000") embedded in generated connection links. Defaults to 56000,56001,9000 if omitted. |
is_deactivated | boolean | When true, new connections with this password are refused with DENIED:deactivated. The bot can toggle this at any time. |
ClientDevice fields
Each key in devices is the device UUID sent by the Android client. The value is a ClientDevice object:
| Field | Type | Description |
|---|
device_id | string | The UUID that identifies this device (sent in the GETCONF handshake). |
ip | string | WireGuard IP address assigned to this device, from the 10.66.0.0/16 subnet. The server itself is 10.66.66.1. |
priv_key | string | Base64-encoded Curve25519 private key generated server-side for this device’s WireGuard peer. |
pub_key | string | Base64-encoded Curve25519 public key corresponding to priv_key. |
down_bytes | integer | Bytes received from this device (via WireGuard IPC polling). |
up_bytes | integer | Bytes sent to this device. |
Password types
Main password
The main password (main_password) is the owner credential. It has no device binding, no expiry, and no limit on concurrent connections. Traffic is tracked separately in the mainPassDown / mainPassUp counters (not stored in devices). The main password is set at deploy time and never appears in the passwords map.
Generated passwords
Up to 10 generated passwords can be active simultaneously. They are created via the Telegram bot (/new command) and support:
- Expiry — a Unix timestamp after which connections are refused and the password is automatically cleaned up by the hourly janitor.
- Device binding — after a device connects and binds, other devices are refused unless
max_devices is greater than 1.
- Deactivation — temporary suspension without deleting the password or its device bindings.
Hot-reload
Edit passwords.json directly on the server, then send SIGHUP to apply the changes immediately:
kill -HUP $(pidof wdtt-server)
On SIGHUP, wdtt-server:
- Re-reads
/etc/wdtt/passwords.json from disk.
- Removes expired passwords and their WireGuard peers.
- Adds or updates WireGuard peers for devices still present.
- Rebuilds the in-memory WRAP key store from all active passwords.
Active tunnels are not interrupted. Traffic continues to flow while the reload completes.
The database is also auto-saved to disk every 60 seconds by the stats loop, so minor changes (traffic counters, new device bindings) are persisted even without a manual hot-reload.
WireGuard subnet and interface settings
| Parameter | Value |
|---|
| Interface name | wdtt0 |
| Server IP | 10.66.66.1/16 |
| Client subnet | 10.66.0.0/16 |
| MTU | 1280 |
| Keepalive | 25 s |
| Key type | Curve25519 |
Client IPs are allocated sequentially from 10.66.0.0/16, skipping 10.66.66.1. Each device receives a /32 allowed-IP entry in the WireGuard peer table.
Command-line flags
wdtt-server accepts the following flags at startup. The deploy script forwards them via the WDTT_ARGS environment variable and the systemd ExecStart line.
| Flag | Default | Description |
|---|
-listen | 0.0.0.0:56000 | UDP/TCP address for the DTLS listener and HTTP Control API. |
-wg-port | 56001 | WireGuard internal UDP listen port (server-side only, not exposed publicly). |
-config-dir | /etc/wdtt | Directory where passwords.json and WireGuard key files are stored. |
-password | — | Main (owner) VPN password. Stored as main_password in passwords.json. |
-admin | — | Numeric Telegram user ID for bot authentication. Required for the bot to start. |
-bot-token | — | Telegram Bot API token from @BotFather. Required for the bot to start. |
-dns | 8.8.8.8 | DNS server address pushed to WireGuard clients in the generated [Interface] config. |
DTLS handshake protocol
When an Android client connects over DTLS, the following text-based exchange takes place over the encrypted DTLS channel before WireGuard traffic is proxied:
GETCONF:<client_port>|<device_id>|<password> — client sends its local WireGuard listen port, a device UUID, and its password.
- Server responds with a WireGuard
[Interface] / [Peer] config block on success, or one of:
DENIED:wrong_password
DENIED:expired
DENIED:deactivated
DENIED:device_mismatch (device limit reached)
NOCONF (IP address pool exhausted — no free IP could be allocated)
READY — client confirms it has applied the WireGuard config.
READY_OK — server confirms, and raw WireGuard UDP traffic is proxied from this point onward.
For clients that already have a config (reconnecting), an AUTH:<device_id> message may be sent instead of GETCONF, skipping re-provisioning.
passwords.json contains WireGuard private keys for every connected device. Restrict access to the file:chmod 600 /etc/wdtt/passwords.json
The deploy script sets this permission automatically, but verify it if you edit the file manually.