STACIO WIKI · Networking Guide

Stacio Tunnels Guide

Applicable version: Stacio 0.14.x
Updated: 2026-07-25
Audience: users who access private services through SSH, create a SOCKS5 proxy, or configure remote reverse forwarding

1. What a tunnel is

Stacio tunnels forward TCP traffic through an existing SSH authentication path. Three types are supported:

Type Data entry Data exit Typical use
Local forwarding Listening address and port on this Mac Target host and port reachable from the SSH host Access an internal database, web console, or private API.
Remote forwarding Listening address and port on the SSH server Target host and port reachable from this Mac Temporarily expose a local development service to a remote environment.
Dynamic forwarding SOCKS5 listening address and port on this Mac Specified per request by the SOCKS5 client Browse or debug several private HTTP/TCP targets.

A tunnel does not create new remote-account permission or bypass firewall, SSH-server forwarding policy, or organizational approval. The feature entry point is controlled by the SSH Tunnels License.

2. Prepare before use

Before starting a tunnel, confirm:

  1. You saved and verified an SSH, SFTP, or SCP session, or have an active usable SSH/SCP connection.
  2. The SSH account and authentication method are valid.
  3. The first connection's host key was checked through a trusted channel.
  4. The target service really listens on its expected address and port.
  5. The local port used by Local or Dynamic is not occupied by another process.
  6. The SSH server permits the required TCP forwarding.
  7. Production access, reverse exposure, and proxy behavior have approval.

Establish an ordinary SSH terminal and make a minimal read-only check first. It separates authentication and SSH issues from target-service issues.

In most cases an SSH entry point is an IP endpoint such as 192.168.1.20:22 or 192.168.1.20:2222; with stable DNS it can be gateway.example.com:22. A tunnel target may be a different private IP or hostname that the SSH host can reach. Do not confuse these roles.

3. Open the Tunnels panel

  1. Choose View > Tunnels or click Tunnels in the toolbar.
  2. The inspector lists saved tunnel configurations.
  3. The table includes type, local endpoint, remote endpoint, state, details, and traffic.
  4. Use New, Edit, and Delete at the top to manage configuration; use a row's Start or Stop control to manage runtime state.

If the entry point is disabled with an entitlement hint, inspect Help > License. Do not bypass entitlement or approval by editing the local database.

4. Create a tunnel

4.1 Quick Add

After clicking New Tunnel, Quick Add accepts:

Quick Add defaults the local listening address to 127.0.0.1 and tries to start after saving. Local and Remote targets accept combined host:port; IPv6 may be written as [address]:port.

Remote reverses the meaning of the two sides compared with Local. After a first Remote configuration, save it and enter the full editor to review every field.

4.2 Full editor

Select a configuration and choose Edit Tunnel to set:

Field Meaning
SSH session endpoint Choose an available endpoint and authentication context from saved SSH/SFTP/SCP sessions.
Configuration ID Locally unique identifier such as tun_prod_db; cannot duplicate another tunnel.
Type Local, Remote, or Dynamic.
Local Host For Local/Dynamic, the Mac listening address; for Remote, the Mac-side target address.
Local Port For Local/Dynamic, the Mac listening port; for Remote, the Mac-side target port.
Remote Host For Local, the SSH-side target address; for Remote, the SSH-server listening address; unused for Dynamic.
Remote Port For Local, the SSH-side target port; for Remote, the SSH-server listening port; unused for Dynamic.

Selecting an SSH Session Endpoint fills Remote Host and Remote Port with that session endpoint. After you edit either manually, the configuration no longer matches the selected endpoint. When the SSH transport endpoint and actual forwarding target differ, first open the correct SSH session so the tunnel uses the current connection context, then enter the real forwarding target.

4.3 Distinguish four address roles

At minimum, distinguish these roles:

Address role Example Meaning
SSH connection endpoint ops@192.168.1.20:22 Stacio uses it for SSH authentication and host-key validation.
Mac local listener 127.0.0.1:15432 Local/Dynamic accepts client connections here on this Mac.
SSH-side target 10.0.0.25:5432 A private service the SSH host continues to reach for Local. db.internal:5432 is also valid.
Remote listener 127.0.0.1:19000 Remote accepts connections on the SSH-server side.

Quick Add's Target is one combined host:port input. The full editor's Local Host, Local Port, Remote Host, and Remote Port are separate fields. Do not put an SSH login endpoint into the database target, and do not put the complete 10.0.0.25:5432 into a full-editor Host field.

5. Local forwarding

5.1 Data flow

Mac application -> local listening address:port -> SSH connection -> private target:port

For example, access a PostgreSQL service 10.0.0.25:5432, which only SSH entry point ops@192.168.1.20:22 can reach:

Field Example
Type Local
Local Host 127.0.0.1
Local Port 15432
Remote Host 10.0.0.25
Remote Port 5432

After starting, a database client on the Mac connects to 127.0.0.1:15432. If an internal database uses DNS, Remote Host can be db.internal, while Remote Port remains separately 5432. The database usually sees the SSH-host side as the source, not the Mac's public address.

5.2 Validate

Make read-only checks in a local Mac terminal:

lsof -nP -iTCP:15432 -sTCP:LISTEN
nc -vz 127.0.0.1 15432

An open port proves that TCP is established, not that the database account, TLS, or query works. Use the target protocol for a minimal health check as well.

6. Remote forwarding

6.1 Data flow

Remote client -> SSH server listening address:port -> SSH connection -> Mac-side target:port

For example, make a Mac development service at 127.0.0.1:3000 available to the SSH server itself on 127.0.0.1:19000:

Field Example
Type Remote
Local Host 127.0.0.1
Local Port 3000
Remote Host 127.0.0.1
Remote Port 19000

On the SSH server, verify read-only with:

ss -lnt | grep ':19000'
curl --fail --max-time 5 http://127.0.0.1:19000/health

Do not default a Remote listener to 0.0.0.0 or ::. Non-loopback listening also depends on SSH-server policies such as GatewayPorts; before exposure, confirm authentication, TLS, firewall, allowed scope, and planned stop time.

7. Dynamic forwarding

7.1 Data flow

SOCKS5 client -> Mac SOCKS5 listening address:port -> SSH connection -> client-specified target

Recommended configuration:

Field Example
Type Dynamic
Local Host 127.0.0.1
Local Port 1080

Configure 127.0.0.1:1080 in a SOCKS5-capable client. To test an HTTP destination:

curl --socks5-hostname 127.0.0.1:1080 --fail --max-time 10 http://service.internal/health

--socks5-hostname resolves hostnames from the SOCKS side, which suits hosts resolved only by private DNS. Direct IP access needs no hostname resolution. A proxy does not mean content encryption: the segment from SSH exit to target still depends on whether the target protocol uses TLS.

8. SSH session context

At start, a tunnel obtains SSH context in this order:

  1. usable SSH connection context in the current workspace;
  2. saved SSH/SFTP/SCP session bound by the tunnel record;
  3. otherwise, it reports that an SSH or SCP session must be opened first.

When the bound session is deleted, changes to an unsupported protocol, has an invalid port, or lacks credentials, edit the tunnel and choose a session again. An SSH context opened through ProxyJump can use the same jump configuration for tunnel runtime, but target and jump host each still perform host-key and authentication flow separately.

9. Start, monitor, and stop

9.1 Start

  1. Select the configuration and check type plus both endpoints again.
  2. Click Start in its row.
  3. Wait for state to change from Starting to Running.
  4. Perform a targeted validation with a local or remote client.

Local and Dynamic check local-port availability at start. Remote listens on the SSH server and uses different local-port checks.

9.2 Runtime state

The panel uses colored states and text for:

Running tunnels poll status every second and show accumulated traffic:

upstream bytes  downstream bytes

Traffic only shows that bytes passed through. It does not prove request success, response correctness, or transaction completion.

9.3 Copy an equivalent SSH command

Choose Copy SSH Tunnel Command from a tunnel context menu to get equivalent ssh -L, ssh -R, or ssh -D text. This copies text only and does not execute it. Without a bound session, target can show placeholder user@host; complete and inspect it before use.

9.4 Stop and quit

10. Automatic reconnect

When runtime detects a broken link, it retries with increasing delay, up to 10 automatic reconnect attempts. The UI shows Reconnecting... (attempt N).

Reconnect restores the tunnel link only; it does not guarantee that a database transaction, HTTP request, file transfer, or long connection through the tunnel resumes from its interruption point.

11. Listening safety

11.1 Use loopback by default

For Local and Dynamic, prefer:

127.0.0.1

This permits connections from the current Mac only. 0.0.0.0, ::, and a LAN interface expose the service or SOCKS5 proxy to other devices. The Dynamic editor warns for a listener other than 127.0.0.1.

11.2 Minimum-exposure principle

11.3 Credentials and logs

Tunnels use authentication from the current or saved Stacio session. Copied SSH commands, diagnostics, and screenshots must not contain passwords, tokens, private-key contents, or private-key passphrases. A changed host key requires stop and independent verification.

12. Troubleshooting runbook

12.1 Cannot start

Check in order:

  1. License is valid.
  2. Type and ports are correct, with a port range of 1...65535.
  3. Current SSH context or a valid bound session exists.
  4. SSH authentication and host key are healthy.
  5. Local/Dynamic local port is not occupied.
  6. SSH server permits TCP forwarding.
  7. Target service is listening and route is reachable.

12.2 Local port is occupied

lsof -nP -iTCP:<port> -sTCP:LISTEN

Confirm the process owner before stopping it or using a different port. Do not kill an unknown process only to start a tunnel.

12.3 Local is running but target is unavailable

12.4 Remote has no listener

12.5 Dynamic client fails

12.6 Reconnects repeatedly

  1. Stop the tunnel manually.
  2. Record first-disconnect time and error details.
  3. Check network, VPN, SSH session, credentials, and host key.
  4. Verify both endpoint services are still listening.
  5. Correct root cause, start manually once, and observe.

13. Completion and shutdown checklist

For production access, follow both Security and Governance and Remote Operations.

This page is part of the English Stacio Wiki.