How to Expose a Local API to the Internet for Development and Testing
You built an API. It runs fine on localhost. Then a teammate needs to test it, a mobile app needs to reach it, or Stripe needs to send a webhook to it. Suddenly localhost is not enough. This guide covers every scenario where your local API needs a public URL and the fastest way to get one.
📋 What's in this guide
Why localhost Is Not Enough
When you start a development server, it listens on 127.0.0.1 or localhost.
That address is private to your computer. Nothing outside your machine can reach it.
This is fine for solo development, but it becomes a hard blocker the moment anyone or anything else
needs to talk to your API.
Deploying to a staging environment for every small change is slow and disconnects testing from the actual code you are writing. A tunnel gives you a public URL for the exact code running on your machine right now, with no deployment step.
How It Works
Localtonet creates an encrypted tunnel between your local machine and a relay server. Anyone who connects to the relay address is forwarded to your local API transparently. Your API never knows the difference. You get a public URL without touching your router, opening firewall ports, or having a public IP address.
Tunnel approach (Localtonet)
- Works from any network including CGNAT
- No router or firewall changes
- HTTPS included automatically on HTTP tunnels
- Live in under 60 seconds
- No deployment, no staging server
Deploy to staging
- Requires a full deployment cycle
- Tests run against deployed code, not local code
- Slower feedback loop
- Costs money for every environment
Option A: HTTP Tunnel (for REST APIs and Web Services)
Use an HTTP tunnel when your API serves HTTP or HTTPS traffic. Localtonet provides a public URL and handles TLS automatically. Your local server can stay on plain HTTP.
Start your local API server
Make sure your API is running and note the port number. For example, an Express app on port 3000, a Flask app on port 5000, or a Laravel app on port 8000.
Create an HTTP tunnel in the dashboard
Log in to localtonet.com/dashboard,
go to Tunnels → New Tunnel, select HTTP,
set the local IP to 127.0.0.1 and the port to your API's port. Click Create.
Localtonet generates a public HTTPS URL for you automatically.
Authenticate and start Localtonet
Run the Localtonet client on the same machine as your API using your AuthToken from Dashboard → My Tokens.
localtonet --authtoken <YOUR_TOKEN>
Your API is now reachable at the HTTPS URL shown in the dashboard. Test it immediately from another machine or browser:
# Replace with your actual tunnel URL
curl https://abc123.localto.net/api/users
# POST request
curl -X POST https://abc123.localto.net/api/orders \
-H "Content-Type: application/json" \
-d '{"item": "keyboard", "qty": 1}'
Option B: TCP Tunnel (for gRPC, WebSockets, or Non-HTTP APIs)
Use a TCP tunnel when your API uses a non-HTTP protocol such as gRPC, WebSockets over a raw TCP connection, database protocols, or any other TCP-based service. TCP tunnels forward raw traffic without protocol inspection.
Create a TCP tunnel
In the dashboard, go to Tunnels → New Tunnel, select TCP,
enter your local port, and click Create.
The relay address will look like example.localto.net:33XX.
Start the Localtonet client
Run Localtonet as described above. The tunnel activates and is ready to accept connections on the relay address.
Connect clients to the relay address
Configure your clients to connect to the relay host and port instead of localhost. All traffic is forwarded transparently to your local service.
By default, TCP ports are assigned dynamically each time. If your clients or CI systems need a stable, unchanging address, reserve a port via Add-ons → Reserved Ports in the dashboard. Combine this with a custom domain for a permanent HTTPS endpoint.
Real-World Scenarios
🪝 Testing Stripe webhooks locally
Create an HTTP tunnel pointing to your local server's port. Copy the HTTPS tunnel URL. In the Stripe dashboard under Developers → Webhooks, add the tunnel URL as a new endpoint. Stripe delivers real payment events to your local code in real time. You see the full payload and can debug your handler without deploying anything.
📱 Mobile app hitting a local backend
Your iOS or Android app in development needs to call your local API. The phone is on mobile data or a different network. Point the app's API base URL to your Localtonet HTTP tunnel URL. The app now communicates with your laptop's server as if it were on the internet.
🔐 OAuth callback URL during development
OAuth providers like Google or GitHub redirect users to your callback URL after login. That URL must be on the public internet and registered in your OAuth app settings. Use your Localtonet tunnel URL as the registered callback and receive OAuth redirects directly in your local app.
👥 Sharing work-in-progress with a teammate
You are halfway through a feature and your backend colleague wants to test their frontend against your changes. Share your tunnel URL. They hit your local API from their machine in seconds. No branch deployment, no Docker setup, no waiting.
🤖 n8n or LangChain calling your local endpoint
You are building an AI agent or automation workflow that needs to call a custom API you are developing. The orchestration tool runs on a different machine or in the cloud. Give it your Localtonet HTTP tunnel URL and it talks to your local API on every workflow run.
🧪 Running integration tests from CI against local code
Your CI pipeline runs tests that call an API endpoint. Instead of deploying a test environment, start a Localtonet tunnel in your CI job and point the test runner at the tunnel URL. Tests run against the exact code in the current commit.
Quick Start by Framework
The steps are the same regardless of what your API is built with. Start the server, create the tunnel, use the URL.
Node.js / Express
// server.js
const express = require('express')
const app = express()
app.use(express.json())
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from local API' })
})
app.listen(3000, () => console.log('API running on http://localhost:3000'))
node server.js
# Now create an HTTP tunnel to port 3000 in the Localtonet dashboard
Python / FastAPI
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/api/hello")
def hello():
return {"message": "Hello from local API"}
uvicorn main:app --port 8000
# Now create an HTTP tunnel to port 8000 in the Localtonet dashboard
Python / Flask
# app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/api/hello')
def hello():
return jsonify(message='Hello from local API')
if __name__ == '__main__':
app.run(port=5000)
python app.py
# Now create an HTTP tunnel to port 5000 in the Localtonet dashboard
Go
// main.go
package main
import (
"encoding/json"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "Hello from local API"})
}
func main() {
http.HandleFunc("/api/hello", helloHandler)
http.ListenAndServe(":8080", nil)
}
go run main.go
# Now create an HTTP tunnel to port 8080 in the Localtonet dashboard
Security During Development
✅ Use HTTP tunnels for automatic HTTPS
Localtonet HTTP tunnels come with a free Let's Encrypt TLS certificate. Your API is served over HTTPS automatically. No certificate setup, no self-signed cert warnings, no extra configuration on your local server.
🔐 Add SSO authentication to your tunnel
If your tunnel URL should only be accessible to specific people, enable Single Sign-On in the tunnel settings in the Localtonet dashboard. Anyone trying to reach your API through the tunnel must authenticate first using Google, GitHub, Microsoft, or GitLab.
⏱ Stop the tunnel when done
Development tunnels should not be left running indefinitely when you are not actively working. Stop the Localtonet client when you are done, or stop the tunnel from the dashboard. Your local API immediately becomes unreachable from the public internet.
🌍 Keep sensitive data out of dev APIs
Avoid using real production data in a locally exposed API. Use seeded test data or anonymized records. The tunnel itself is encrypted, but the endpoints on your local API may not have the same authentication and rate limiting as your production service.
Frequently Asked Questions
My API is on a different machine on the same network. Can I still tunnel it?
Yes. When creating the tunnel, set the local IP to the IP address of the machine running the API instead of 127.0.0.1. For example, 192.168.1.50 and port 3000. Localtonet will forward traffic to that address on your local network.
Will the tunnel URL change every time I restart Localtonet?
For HTTP tunnels, the subdomain can be made permanent by reserving it in the dashboard. For TCP tunnels, reserve a port via Add-ons → Reserved Ports to get a fixed address. You can also attach a custom domain for a completely stable HTTPS URL that never changes.
Does this work with APIs that use WebSockets?
Yes. Localtonet HTTP tunnels support WebSocket connections (WS and WSS). Clients can upgrade to WebSocket using your tunnel URL the same way they would on a regular HTTPS server.
Can I expose multiple API ports at the same time?
Yes. Create a separate tunnel for each port in the dashboard. Each tunnel gets its own public URL. Run a single Localtonet client instance and it handles all tunnels associated with your account simultaneously.
My API requires HTTPS but I'm running it on HTTP locally. Will it work?
Yes. Use an HTTP tunnel. Localtonet handles TLS termination at the relay and forwards plain HTTP to your local server. Clients see a valid HTTPS URL. Your local server does not need to handle TLS at all.
Does exposing my local API slow it down?
There is a small amount of added latency because requests travel through the Localtonet relay server. In practice this is unnoticeable for development and testing. For production traffic or latency-sensitive benchmarks, a direct connection is always faster.
Get a Public URL for Your Local API in Under a Minute
Create a free Localtonet account, start your API server, and open a tunnel. Webhooks, mobile apps, teammates and integrations can all reach your local API instantly.
Create Free Account →