Docs / Connect to Hosts
Port forwarding & tunneling
SSH port forwarding lets you reach a service that isn't exposed to the internet by tunnelling its traffic through an encrypted connection you already trust — a private database, an internal web UI, or your whole browsing session.
What port forwarding is
When you open an SSH connection, you build an encrypted channel between your device and a remote server. Port forwarding reuses that channel to carry other traffic. Instead of opening a separate, exposed port on a firewall, you wrap the service inside the SSH session you're already authenticated to. Nothing extra is published to the public internet; the service stays private and only your verified session can reach it.
NetShell supports the three standard forwarding modes — local, remote, and dynamic (SOCKS). Each solves a different problem. The trick is knowing which direction the traffic needs to travel.
Local forwarding — pull a remote service to your device
Local forwarding is the one you'll use most. It takes a port on your iPhone, iPad, or Mac and connects it, through the SSH tunnel, to a host and port reachable from the server. You then point an app on your device at the local port, and the traffic comes out the far end of the tunnel.
local port (on your device) --ssh tunnel--> server --> target:port
127.0.0.1:5432 db.internal:5432
Use local forwarding when the thing you want lives behind the server's firewall and you want to use it from your device. Classic cases: connecting a database client to a Postgres or MySQL instance that only listens on the private network, or opening an internal admin dashboard in your browser.
Remote forwarding — push a service out to the server
Remote forwarding is the mirror image. It opens a port on the server and forwards anything that connects to it back through the tunnel to a host and port reachable from your device. It's how you expose something running locally so a remote machine — or other people who can reach that server — can use it.
server listens <--ssh tunnel-- your device --> local target
0.0.0.0:8080 localhost:3000
Reach for remote forwarding when the traffic needs to flow toward the server: letting a teammate hit a dev build running on your machine, or giving a remote process a way to call back to a service on your side of the connection.
Dynamic forwarding (SOCKS proxy)
Dynamic forwarding turns the tunnel into a general-purpose SOCKS proxy. Instead of mapping one fixed target, it opens a single local port that can route traffic to any host the server can reach, deciding the destination per-request. Point a browser or app at the SOCKS port and everything it sends travels encrypted through the server and exits from there.
app --> SOCKS proxy --ssh tunnel--> server --> anywhere the server can reach
127.0.0.1:1080 (chosen per request)
Use dynamic forwarding when you don't want to define a rule per service — for example, browsing several internal web apps through one tunnel, or sending your traffic out via a server in another network. It's the most flexible mode and the right default when "I just need to be on that network" is the goal.
Configuring a forwarding rule
Forwarding rules attach to a saved connection, so the tunnel rides on top of an SSH session you've already set up (see Add a connection).
- Open the connection in the editor and find the Port forwarding section.
- Add a rule and choose its type: Local, Remote, or Dynamic.
- For local and remote, set the listen port (the side that opens the entry point) and the target host and port (where the traffic comes out).
- For dynamic, you only set the local SOCKS port — there's no fixed target.
- Give the rule a recognisable name, save, and connect. The tunnel comes up with the session.
Because the rule lives on the connection, all of NetShell's connection security applies: host verification at handshake time that fails closed (credentials are never sent to an unknown or changed host), credentials drawn from the hardware-backed iOS Keychain and unlocked with Face ID, and auto-relock after idle. A tunnel is only ever built on top of a host you've explicitly trusted.
Auto-start with the session
A forwarding rule saved on a connection starts automatically whenever that connection opens, so you don't re-create the tunnel each time. Open the connection, the rule activates; close it, the listening port is torn down with the session. To make a forward part of your routine, define it once on the connection and leave it enabled. For chained connections, the forward is established on the final session — see Jump hosts for how multi-hop sessions are built.
Example — database tunnel
Suppose Postgres runs on db.internal:5432, reachable only from your jump or app server, and you want to query it from a client on your device.
- Open (or create) the connection to the server that can reach the database.
- Add a Local forwarding rule: listen port
5432, target hostdb.internal, target port5432. - Save and connect. Your client now points at
127.0.0.1:5432and talks to the private database through the encrypted tunnel.
# What the client sees # What actually happens
psql -h 127.0.0.1 -p 5432 => encrypted SSH tunnel => db.internal:5432
The database never needs a public port, and the only path to it is your verified, Face ID-protected session.
Example — internal web UI over SSH
Say an admin dashboard listens on 10.0.0.20:8080 inside a private network. To open it in your browser:
- Add a Local rule on the server connection: listen port
8080, target host10.0.0.20, target port8080. - Connect, then browse to
http://127.0.0.1:8080.
If you need to reach several internal sites at once, skip the per-service rules and use a Dynamic forward instead: open a SOCKS port, set your browser to use it as a proxy, and every internal address resolves through the server.
Forwarding vs. the built-in tools
You don't always need a forward. NetShell already speaks several protocols natively, and using the built-in tool is simpler when it fits:
- For files, use the SFTP browser or SMB file shares rather than forwarding a file-transfer port.
- To find what's listening before you tunnel, the network scanner finds devices and detects SSH servers and open ports.
- For container logs and control, the Docker tools manage containers and Compose stacks directly over the session.
Use forwarding for everything else — databases, web UIs, message queues, and any TCP service that doesn't have a dedicated screen.
Troubleshooting
- Local port in use. If another app already holds the listen port, pick a different one (for example
15432instead of5432) and point your client there. - Tunnel comes up but the service doesn't answer. Confirm the target host and port are reachable from the server, not just from your device — the far end of the tunnel does the connecting.
- Remote forward not reachable. The server's own configuration governs whether a remote-forwarded port can accept outside connections; if only the server itself can reach it, that's the server's policy, not the tunnel.
- Forward drops when the session ends. That's expected — the listening port lives and dies with the SSH session. Re-open the connection (or rely on auto-start) to bring it back.
- Unexpected fingerprint prompt. A new host-key approval on a server you've used before means the key changed; the handshake fails closed before any credential or tunnel traffic is sent. Verify before approving — see Host verification.
NetShell is a free SSH client for iPhone, iPad & Mac — no subscription, no telemetry by default. Download NetShell on the App Store.