TCP Tunnels
A step-by-step guide to reaching a local TCP service over the internet with Localport. Give a game server, a local LLM, PostgreSQL, Redis, or SSH a public host and port that anyone you choose can connect to. Covers reserved ports, custom subdomains, and IP allowlists.
Summary
minecraft-world.eu.localport.dev:47266 that friends, clients, and remote apps can connect to. Works for game servers, local LLMs, databases, SSH, and any custom protocol.How a TCP tunnel works#
A TCP tunnel carries raw bytes. Localport gives your tunnel a host and a dedicated port, listens there, and forwards every connection straight to the port on your machine. Nothing in the middle parses, rewrites, or inspects the traffic, so a protocol that is not HTTP works exactly as it does on your own network: Minecraft, PostgreSQL, SSH, VNC, MQTT, or a binary protocol you wrote yourself.
The connection is outbound from your machine to Localport, the same kind of connection your browser makes. There is no port to forward on your router, no inbound firewall rule, and no VPN, so it works behind NAT, CGNAT, university networks, and mobile hotspots.
TCP addresses are a host AND a port
host:port, for example minecraft-world.eu.localport.dev:47266. Both parts matter: whoever connects needs the port too. You can pin both so the address never changes (see Give your tunnel a permanent address).To follow along you need a Localport account and a service listening on a local TCP port.
Step 1: Create a TCP tunnel in the dashboard#
Open dashboard.localport.io, go to Tunnels, and click New. The create panel slides in and asks for:
- Name. A label so you can tell your tunnels apart. You can rename it later.
- Region. Where your tunnel is served from: EU, US, or Asia Pacific. For a game server, pick the region closest to the players, not to you.
Click Create.
There is no protocol choice at this step. A tunnel becomes a TCP tunnel when you run it with the tcp protocol, which the connect step sets for you.
Step 2: Install the agent#
The tunnel exists, but nothing is serving it yet. Install the Localport agent on the machine your service runs on: one dependency-free binary for macOS, Linux, and Windows. Follow Installation, then confirm it with localport --version.
The agent is open source
Step 3: Copy your connect command#
The dashboard moves to the Connect step and builds the command. Two controls matter most for TCP:
- Preset. One click fills in the protocol and port for a known service: Minecraft, PostgreSQL, Redis, SSH, MongoDB, and a dozen more. Anything else, pick Custom and type the port.
- Protocol. Set to TCP, which carries the bytes exactly as your service sends them.
The rest is the same as any tunnel: Local Address (defaults to localhost), Custom Name, No UI for servers and CI, and your Token.
Copy the finished command. For a Minecraft server it looks like this:
localport tcp 25565 --token tok_k8f2 --region eu
tcpis the protocol, for anything that is not HTTP.25565is the local port your service listens on.--tokenauthenticates the tunnel.--regionmatches the region you chose:eu,us, orap.
The CLI reference documents every flag and form.
Step 4: Run the tunnel#
Paste the command into your terminal and press Enter. The tunnel connects and the terminal turns into a live status panel.
- Forwarding is your public address. Everything after
tcp://is what you hand out: host and port. - Local is the port on your machine that traffic is carried to.
- Bandwidth and Connections update live, with a per-connection breakdown of IP, duration, and bytes in and out. On a game server that is a live player count.
Leave the command running. As long as it runs, the address is live. Press Ctrl+C to stop it; connections drop immediately and the tunnel stays saved to your account.
Step 5: Connect from anywhere#
Hand out the host and port from Forwarding. The tcp:// prefix is there to tell you the protocol; clients do not want it. For the Minecraft server above, a friend on the other side of the world chooses Multiplayer, Add Server, and pastes:
minecraft-world.eu.localport.dev:47266
Every other client takes the same two values in its own syntax:
# PostgreSQL
psql -h your-tunnel.eu.localport.dev -p 47266 -U myuser mydb
# SSH
ssh user@your-tunnel.eu.localport.dev -p 47266
# Anything at all, to check it answers
nc -vz your-tunnel.eu.localport.dev 47266
Nothing on the other end knows a tunnel is involved. To your database client it is a host and a port like any other.
Give your tunnel a permanent address#
Both halves of a TCP address are yours to pin, in the tunnel's General settings.
Pick your own subdomain
The Subdomain field is the word in front of the address, and you choose it. Type minecraft-world and the address becomes minecraft-world.eu.localport.dev. The dashboard checks the name while you type and tells you whether it is free, since subdomains are unique across Localport. It is saved to your tunnel, so it survives restarts and reads the same tomorrow.
Reserve the port
By default a tunnel gets a port when it connects. Click Reserve in the Port field and that number becomes yours: the same port every session, so an address you shared last month still works. Reserve it once and stop editing the connection string in five different places.
Reserve before you share
.env should never need editing again.Lock down who can connect#
A TCP address is open to anyone who has it, so restrict it. Open the tunnel and find Network & Security in its settings, change what you need, and click Save.
Restrict who can reach it with an IP allowlist
Enter one or more IP addresses or CIDR ranges in Inbound IP Whitelist (for example 203.0.113.4, 198.51.100.0/24) and only those addresses can connect. To everyone else the port does not answer at all. Leave it blank to allow anyone.
This is the main lock on a TCP tunnel, and it is the right one for a database, an SSH port, or a local LLM you are reaching from one known machine. For a game server, leave it blank so friends can join, and rely on the game's own allowlist instead.
Limit where the tunnel can start from
Network IPs restricts the other direction: the tunnel can only be brought online from the listed addresses or ranges, so a leaked token cannot be used to run your tunnel from somewhere else. Leave it blank to allow any location.Need certificates instead of IP addresses?
Another example: reach your local LLM#
A model server is a good second example, because it shows the shape of every TCP tunnel: one port in, one address out. Ollama listens on 11434, so the machine with the GPU runs:
localport tcp 11434 --token tok_k8f2 --region eu
Now your laptop, your phone, or a script on a server can use the model at home. Point any OpenAI-compatible client at the tunnel address:
export OPENAI_BASE_URL=http://ollama-gateway.eu.localport.dev:47266/v1
The model, the weights, and the GPU stay on your machine. Your prompts go to your own hardware and nowhere else.
A model server has no login of its own
The local LLM guide covers editor and agent setups in full.
What else people tunnel this way#
Same three steps every time, only the port changes:
- Game servers. Minecraft on
25565, Terraria on7777, Valheim on2456. Friends join from anywhere and your router stays untouched. See the game server guide. - A database. PostgreSQL on
5432, so a teammate or a staging app can query the copy on your machine instead of waiting for a dump. - SSH. Port
22, for a shell on the machine at your desk from a cafe, with no VPN in the way. - A remote-controlled browser. Chrome started with
--remote-debugging-port=9222takes Playwright and Puppeteer over that port, so a script or a CI job elsewhere can drive the browser sitting on your machine, cookies, extensions, logged-in sessions and all. - Your desktop. VNC on
5900or RDP on3389, for the machine you left at home. - Devices in the field. MQTT sensors, a 3D printer, a NAS, a home server. See the homelab and IoT guides.
- Whatever you wrote yourself. A custom binary protocol tunnels the same way. The bytes arrive as you sent them, so nothing needs to know a tunnel is involved.
Forward to a service on another machine#
By default the CLI forwards to localhost. To reach a service on another host on your network, a NAS, a Raspberry Pi, or a container, pass an explicit address with --local and the tcp:// scheme:
localport --token tok_k8f2 --local tcp://192.168.1.50:5432 --region eu
You can set the same thing in the connect panel with the Local Address field. This is how one machine fronts a whole homelab. See the homelab guide.
Frequently asked questions#
What is the difference between a TCP tunnel and an HTTP tunnel?
An HTTP tunnel understands HTTP: it terminates HTTPS with a real certificate and gives you a https:// URL, plus HTTP-only features like basic auth and Force HTTPS. A TCP tunnel moves raw bytes and gives you a host:port address, which is what non-HTTP protocols need. Use HTTP for web apps and APIs, TCP for databases, game servers, SSH, and custom protocols. See HTTP tunnels.
Can I use the same port every time?
Yes. Click Reserve in the Port field of the tunnel's settings and that port is held for your tunnel, so the address is identical after every restart. Pair it with your own subdomain and the full host:port never changes.
Can I choose my own subdomain for a TCP tunnel?
Yes. Set the Subdomain field in the tunnel's General settings to any available word and the address becomes <your-word>.<region>.localport.dev. Availability is checked as you type, since subdomains are unique across Localport.
How do I host a Minecraft server without port forwarding?
Run localport tcp 25565 --token YOUR_TOKEN --region eu on the machine running the server, then give friends the host and port shown under Forwarding. The connection is outbound from your machine, so no router configuration or static IP is involved. Reserve the port first so the address stays the same. See the game server guide.
Can I expose Ollama or another local LLM?
Yes. Tunnel the model server's port (Ollama uses 11434) and point any OpenAI-compatible client at the address. Because these servers have no authentication of their own, set an inbound IP allowlist first. See the local LLM guide.
Is TCP tunnel traffic encrypted?
The link between your machine and Localport is encrypted. Beyond that a TCP tunnel is a faithful pipe: it carries exactly what your service sends, so a plaintext protocol stays plaintext end to end. Use a protocol that encrypts itself (SSH, or a database with TLS enabled), or a locked tunnel, which requires a client certificate before any byte reaches you.
My service already has its own TLS certificate. Does that work?
Yes. Run it with the tls protocol instead of tcp and the encrypted bytes pass through untouched, so the certificate clients see is still yours. Everything on this page (subdomain, reserved port, IP allowlists) applies unchanged. The CLI reference lists every protocol.
How many people can connect at once?
As many as your service handles. Each inbound connection is proxied to your local port independently, and the status panel shows live connection count and per-connection bandwidth, so a full game server or a shared database behaves the way it does on your LAN.
Does it work behind NAT, CGNAT, or a corporate firewall?
Yes. The tunnel is an outbound connection from your machine, so there is nothing to open inbound. It works on home routers, mobile hotspots, dorm networks, and corporate connections where port forwarding is not an option.
What to read next#
- Game Servers. Full setup for Minecraft, Valheim, Terraria, and more.
- Local LLM. Reach Ollama and other model servers from anywhere.
- Homelab Remote Access. Front a whole home network from one machine.
- HTTP & HTTPS Tunnels. Public HTTPS URLs for web apps and APIs.
- Locked Tunnels. Require a client certificate before any byte reaches you.
- CLI. Every flag, option, and exit code.