DEV Community

Harpreet Singh
Harpreet Singh

Posted on

📲Build Your Own SMS OTP Sender Using Termux + Python + Port Forwarding

Ever wondered how OTP systems work? In this blog, we’ll build a simple SMS OTP Sender using your Android phone, Termux, and a little bit of Python magic. It’s a fun way to learn about messaging automation, APIs, and port forwarding — especially if you're a beginner in backend or ethical hacking!

🛠️ Tools & Technologies Used

  1. Termux (Android) – Linux terminal emulator for Android.
  2. Termux: API – Provides access to Android’s native APIs like SMS.
  3. Python – To build a simple backend script.
  4. Flask – Lightweight Python web framework.
  5. Cloudflare Tunnel / Ngrok – To expose the local server to the internet.

📦 Step 1: Setup Termux on Android

Install Termux from F-Droid (not Play Store):

pkg update && pkg upgrade
pkg install python
pkg install termux-api
pip install flask

Enter fullscreen mode Exit fullscreen mode

Also install Termux API app from F-Droid (important).

Step 2: Write the SMS Sender in Python

Create a file called sms_sender.py:

import json
import os
from http.server import BaseHTTPRequestHandler, HTTPServer

class RequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path == "/send-sms":
            content_length = int(self.headers["Content-Length"])
            post_data = self.rfile.read(content_length)
            data = json.loads(post_data)

            phone = data.get("phone")
            otp = data.get("otp")

            if phone and otp:
                command = f'termux-sms-send -n {phone} "Your OTP is {otp}"'
                print(f"Executing: {command}")  # Debugging statement

                # Use os.system to execute the command
                result = os.system(command)

                # Check the result code
                if result == 0:
                    print("✅ SMS sent successfully!")
                    self.send_response(200)
                    self.end_headers()
                    self.wfile.write(json.dumps({"message": "OTP Sent"}).encode())
                else:
                    print("❌ Failed to send SMS! Error code:", result)
                    self.send_response(500)
                    self.end_headers()
                    self.wfile.write(json.dumps({"error": "Failed to send SMS"}).encode())
            else:
                self.send_response(400)
                self.end_headers()
                self.wfile.write(json.dumps({"error": "Invalid data"}).encode())

server_address = ("", 8080)  # Running server on port 8080
httpd = HTTPServer(server_address, RequestHandler)
print("📡 Termux SMS Server running on port 8080...")
httpd.serve_forever()
Enter fullscreen mode Exit fullscreen mode

🌐 Step 3: Port Forward with Cloudflare Tunnel

When you're building a local project, your services usually run on your machine and are only accessible from your own device. For example:

  • Your frontend (React, etc.) runs on localhost:3000
  • Your backend server runs on localhost:8080
  • Your database runs on localhost:5432

But here’s the problem:
These localhost ports are not accessible from outside your machine.

So, how do you access your local app from another device? Or share it with a team member or webhook service?

You have two options:

Buy a domain + server, deploy your services, and make them public.

Or — use port forwarding with tunneling services like Cloudflare Tunnel or ngrok.

🔁 What is Port Forwarding?

Port forwarding is a method to expose a specific port (running locally) to the internet, by tunneling it through a public URL.

👉Example: Cloudflare Tunnel for Port Forwarding

Let’s say we’re working on a full-stack app that runs locally like this:

3000 → Frontend (React app)

8080 → Backend Server (API)

5432 → PostgreSQL Database

Here's a visual representation of our local setup:

exposing localhost using tunnel

As shown in the image:

All services are running locally.

We use a Cloudflare Tunnel to expose these local ports to the outside world.

This tunnel creates a public URL that anyone can access — just like a real deployed app.

To forward your local Flask server (running on port 8080), use:

cloudflared tunnel --url http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

🧪 Step 4: Test the SMS API

Here once the Cloudflare Tunnel was set up and pointing to to my Termux Flask server, we need a way to trigger rigger the OTP sending from my backend. So I created an API route that would generate an OTP, save it in the database for short duration, and send a request to my Termux SMS server to deliver the OTP to the user’s phone.

Here's how I tested it:

📡 Make a POST request to the Termux server

I exposed the Termux Flask server (running on my phone) using Cloudflare Tunnel. Then, I hit this public URL with a simple POST request:

POST https://yourname.trycloudflare.com/send-sms
Content-Type: application/json

{
  "number": "9876543210",
  "message": "Your OTP is 6789"
}
Enter fullscreen mode Exit fullscreen mode

You can do this using Postman, or directly from terminal with curl:

curl -X POST https://yourname.trycloudflare.com/send-sms \
-H "Content-Type: application/json" \
-d '{"number": "9876543210", "message": "Your OTP is 6789"}'
Enter fullscreen mode Exit fullscreen mode

And boom 💥 — the message is sent directly from my Android phone using Termux’s native termux-sms-send command.

This worked great for me during testing — no need for third-party SMS providers or paid APIs. I used this method to automate OTP delivery in my full-stack app.

📌 TL;DR

In this blog, I built a DIY SMS OTP sender using just:

  • An Android phone running Termux
  • A Python + Flask server to send SMS via termux-sms-send
  • A Cloudflare Tunnel to expose the local API publicly

I also connected this setup with a backend (Node.js + MongoDB) that:

  • Generates an OTP
  • Stores it temporarily
  • Verifies it securely when submitted

This project avoids third-party SMS services, is perfect for local development/testing, and helps you understand port forwarding, automation, and full-stack OTP systems using open tools.

Top comments (0)