The Problem
Tally ERP runs as a desktop application on a local Windows computer inside an office. It has no REST API, no public URL, and no way to reach it from the internet. The machine sits behind a router with a dynamic IP — completely invisible from outside.
I needed a mobile app to send a request to Tally and get a live response. Not a sync later — right now.
The Solution
I built a small desktop application called the Connector that runs on the same machine as Tally. When it starts, it establishes a persistent outbound connection to my VPS using a reverse proxy tunneling tool running on the server side. Outbound — so it works behind any router or firewall with zero network configuration or port forwarding on the client side.
This connection exposes Tally's local port as a unique URL on the VPS. That URL is automatically saved to the database — it never appears in the app, never goes to the client, and is only used internally by the backend. When a request arrives from the mobile app, the backend fetches that URL from the database and proxies the request through it. The Connector receives it, sends it to Tally as an XML request over localhost, and the response travels back the same way.
"The machine calls out to the VPS once. That creates a live public URL for Tally's localhost — stored in the database, invisible to the outside world."
📱 Mobile App (Flutter)
User triggers a Tally data request
☁️ Backend API
Validates JWT, fetches tunnel URL from DB
🌐 VPS — Reverse Proxy Tunnel
Routes request through the persistent outbound channel
🖥️ Connector (Desktop App)
Runs on the same Windows machine as Tally
📊 Tally ERP
Processes the XML request and returns live data
Security
The tunnel identifier is never sent to any client — it only exists inside the backend. On top of that, every request requires a valid JWT token. Two layers: the tunnel is hidden, and even if someone found it, they still cannot use it without authentication.
Hidden Tunnel URL
The tunnel identifier is stored server-side in the database. No client ever sees it.
JWT Authentication
Every request must carry a valid token. Even knowing the tunnel URL is not enough.
Outbound-Only Connection
The office machine initiates the connection. No inbound ports are opened on the local network.
Self-Hosted Infrastructure
No third-party tunneling service sits in the data path. Full control over the entire chain.
Why Not Ngrok
Ngrok and similar hosted tunneling services work fine for demos. For production, free tier URLs change on every restart, paid plans have rate limits, and you are entirely dependent on their infrastructure staying up. Running the tunnel server on a VPS I control means the URLs are stable for as long as the Connector is running, the security is exactly what I designed, and there is no third-party in the middle of the data path.
| Feature | Ngrok (Free) | Ngrok (Paid) | Custom VPS Tunnel |
|---|---|---|---|
| URL Stability | Changes on restart | Stable subdomain | Stable while running |
| Rate Limits | 40 connections/min | Higher, but capped | No limits |
| Data Path Control | Third-party sees all traffic | Third-party sees all traffic | Fully self-hosted |
| Cost | Free | ~$20/month | VPS cost only (~$5/mo) |
| Custom Security | No | Limited | Full control |
The Key Insight
Reaching a machine behind NAT from the outside is hard. But letting that machine initiate the connection outward — and then keeping that channel alive to serve inbound requests through it — is straightforward and reliable. Once the Connector is running, Tally's localhost effectively has a public address. The backend just reads it from the database and uses it like any other URL.