01How it works
Your PC GCP VM (hub-server) Phone (Termux) ssh -p 2223 ───────────► 136.67.4.216:2223 ──reverse──► localhost:8021 / 8022 ▲ tunnel dialed OUT by the phone ▲ (sshd)
Because the phone initiates the connection, this works from behind carrier NAT
and firewalls. The VM only relays raw TCP; the SSH session inside stays
end-to-end encrypted. One VM serves many phones — each takes a
different public port in the range 2222–2240, so a single
list-phones command shows everyone online.
02The portal & accounts
A Django + DRF + django-allauth site lives at
http://<vm-ip>/gcprelay. It provides:
- Login by username, email, or mobile number + password — a single multi-identifier backend.
- TOTP email & mobile verification. A rotating 6-digit code is printed to the server console and appended to an SSH-readable file, so the operator reads it without any SMS/SMTP gateway.
- Forgot / reset password via the same TOTP-to-file mechanism.
Read a code over SSH:
$ tail -n 3 ~/gcprelay/otp_codes/email_otps.txt [2026-07-15 09:12:04] purpose=email user=karthik target=k@example.com CODE=144648 (valid ~5 min)
03REST API
Everything the web forms do is also exposed under /gcprelay/api/
for scripting (token auth).
| Method & path | Body |
|---|---|
POST /register/ | username, email, mobile_number, password |
POST /login/ | identifier, password → token |
POST /otp/email/request/ | identifier |
POST /otp/email/verify/ | identifier, code |
POST /otp/mobile/request/ | identifier |
POST /otp/mobile/verify/ | identifier, code |
POST /password/reset/request/ | identifier |
POST /password/reset/confirm/ | identifier, code, new_password |
04The scripts
All are argument-driven and downloadable from the portal. Bundled with the repo.
Provision the VM provision-vm.sh
Autonomous VM builder: gcloud install & sign-in, project, billing, Compute API, free-tier e2-micro, firewall range, sshd tweaks, list-phones.
bash provision-vm.sh \ --project my-proj --create-project \ --billing-account XXXXXX-XXXXXX-XXXXXX
Deploy the portal deploy-site.sh
Hosts this site behind gunicorn + nginx at /gcprelay
— venv, migrate, collectstatic, systemd service.
sudo bash deploy-site.sh \ --host 136.67.4.216 --superuser admin
Onboard a phone gcp-phone-setup.sh
Termux-native: key-only Termux sshd + self-healing tunnel. Pre-checks the port is free on the VM before starting.
bash gcp-phone-setup.sh --port 2223 \ --vm-key ./google_compute_engine \ --pc-pubkey ./pc-access-key.pub
Onboard (Ubuntu) gcp-phone-setup-ubuntu.sh
For a phone already running Ubuntu-in-Termux. Auto-detects proot-distro or start-ubuntu22; tunnels the Ubuntu sshd on 8021.
bash gcp-phone-setup-ubuntu.sh --port 2224 \ --vm-key ./google_compute_engine \ --pc-pubkey ./pc-access-key.pub
Take a phone offline gcp-phone-teardown[-ubuntu].sh
Stops the relay + sshd and frees the VM port immediately so
the next phone can claim it. --disable-autostart to decommission.
bash gcp-phone-teardown.sh --port 2223
The tunnel loop gcp_relay.sh
The keep-alive each phone runs. Singleton per port via flock;
reconnects in ~5s if the tunnel drops. self-healing
bash gcp_relay.sh 136.67.4.216 2223
05Quick start
Provision the VM
Run provision-vm.sh. It prints the VM's
external IP and opens the relay ports.
Deploy the portal
On the VM, run deploy-site.sh --host <ip>,
then open tcp:80 in the firewall. Visit http://<ip>/gcprelay.
Onboard a phone
Copy the setup script, the VM key, and your PC public key to the
phone, then run the setup command with a free --port.
Connect
ssh -i pc-access-key -p <port> <user>@<vm-ip>
— you're on the phone.