How Portex Works: The Magic Behind Exposing Localhost
Have you ever wondered what actually happens when you type portex start --port 3000?
In seconds, a service running only on your laptop is suddenly accessible to anyone in the world. It feels like magic, but under the hood, itβs a carefully orchestrated symphony of WebSockets, Reverse Proxies, and Secure Tunnels.
In this post, Iβll peel back the layers and explain the architecture of Portex, an open-source alternative to ngrok built with Go and Laravel.
Phase 1: The Initial Handshake π€
When you run the Portex CLI (built in Go), it doesn't just open a connection blindly. First, it introduces itself to the Portex Server.
- Authentication: The CLI sends your API key/secret to authenticate. If you're a first-time guest, it can even register partially anonymously.
- Protocol Upgrade: Once authenticated, the CLI initiates a standard HTTP request to the server, but with a special header:
Upgrade: websocket. - The Persistent Tunnel: The server accepts this and effectively "hijacks" the TCP connection, turning it into a long-lived, full-duplex WebSocket connection. This is our secure tunnel.
Unlike traditional HTTP requests that open and close, this WebSocket connection stays alive, beating regularly (heartbeat) to ensure the path remains clear even through NATs and firewalls.
Phase 2: The Public Gateway π
Now, let's say a user from Japan visits https://myapp.portex.space. Here's the journey of that request:
- DNS Resolution: The browser resolves
*.portex.spaceto our ingress server. - Reverse Proxy (The Brain): Our server (written in Go) receives the request. It looks at the Subdomain (
myapp) and checks its internal memory map: "Do I have an active agent connection for 'myapp'?" - Routing: If the agent is found, the server allows the request to proceed. If the tunnel is PIN-protected, it pauses here to ask for the password.
Phase 3: The Relay πββοΈ
This is where the speed of Go shines. The server needs to forward the visitor's HTTP request down the WebSocket tunnel to your laptop. But you can't just shove raw HTTP over a WebSocket frame easily.
Portex serializes the request (Headers, Body, Method) into a compact JSON (or binary) payload and pushes it through the active WebSocket connection to your CLI agent.
Phase 4: Local Execution π»
Your laptop (the Agent) receives this message.
- Reconstruction: It reads the payload: "Oh, someone wants
GET /api/users." - Local Fetch: The Agent makes a real HTTP request to your local service running at
localhost:3000. - The Response: Your local API responds (e.g., 200 OK with a JSON body).
- Echo Back: The Agent captures this response, serializes it again, and shoots it back up the tunnel to the Server.
Finally, the Server unpacks it and serves the response to the user in Japan. All of this happens in milliseconds.
Why Go + Laravel? π οΈ
We chose a hybrid architecture for Portex:
- Go (Golang): Handles the high-concurrency data plane (the Tunnels). Itβs perfect for managing thousands of active WebSocket connections with minimal memory footprint.
- Laravel: Manages the control plane. User accounts, billing, dashboard interfaces, and analytics are handled by the robust PHP ecosystem.
Conclusion
Portex isn't just "another tunneling tool." It's a modern, developer-first approach to a classic problem, designed to be as transparent and secure as possible.
Ready to see it in action?
π Install: curl -fsSL https://portex.space/install.sh | bash
π Star us on GitHub: github.com/portex/portex
Happy tunneling! π
Related Posts
Introduction to DevOps: Setting Up CI/CD Pipeline
Learn how DevOps culture, tools, and practices are transforming software development processes.
Web Application Security Best Practices
Security should be a top priority in web development. Learn about common vulnerabilities.