Skip to content

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

Give anything on your machine that speaks raw TCP a public address, over the internet, with one command. Create a tunnel in the dashboard, copy the command it builds, and get a fixed host and port like 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

An HTTP tunnel gives you a URL. A TCP tunnel gives you 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.

Set up the tunnel, then the dashboard builds the exact command to run.

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

The agent is the only Localport component that runs on your machine, and it is Apache 2.0 licensed at github.com/localport/agent. Read it, build it yourself, or pin the version you audited.

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
  • tcp is the protocol, for anything that is not HTTP.
  • 25565 is the local port your service listens on.
  • --token authenticates the tunnel.
  • --region matches the region you chose: eu, us, or ap.

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.

Run the command and the tunnel connects, with your public host and port under Forwarding.
  • 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.

Type a subdomain and the dashboard checks it as you type, then Reserve pins the port.

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

Set the subdomain and reserve the port before you hand the address out. A game server address in a group chat, an SSH config entry, or a database connection string in a teammate's .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.

The Network & Security section on a TCP tunnel: two IP allowlists, one for each direction.

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?

An IP allowlist is fixed to a network. When you need each connecting client to prove its identity with a certificate you issued and revoke, use a locked tunnel, which requires mutual TLS before a single byte reaches you.

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

Ollama and its neighbours answer anyone who reaches them, so the tunnel address is the only thing between the internet and your GPU. Set an inbound IP allowlist to the addresses you actually connect from before you leave it running.

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 on 7777, Valheim on 2456. 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=9222 takes 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 5900 or RDP on 3389, 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.