Skip to content
  • MangoFly

    A self-hosted WireGuard mesh. Devices connect straight to each other; the coordination server is one binary and a SQLite file, and never sees their traffic.

    encrypted WireGuard · peer to peerLaptopbehind home NATServerin a datacentrePhoneon mobile datacoordination serverone binary · one SQLite filecontrol plane only (TLS)keys · tunnel addresses · peer lists · sealed ICE candidatesholds no private keys · carries no traffic · cannot decryptdatacontrol
  • MangoDock

    Docker management with nothing on the hosts. Reaches each daemon over an ordinary SSH session — no agent to install, no port to open.

    The MangoDock dashboard showing three host cards with container state counts, CPU and memory gauges, a usage history and recent events
  • MangoWiFi

    A Wi-Fi 6/7/8 test bench. One binary runs as Console or Agent either side of the access point under test, measuring latency under real load.

    AP under testWi-Fi 6 / 6E / 7Agentstation side · real radioLAN receiveriperf3 -sConsoleUI · orchestrates · probes
  • Blog
  • Nothing phones home

    No telemetry, no analytics, no crash reporter, no account login. Check it with a packet capture on your own network.

    Download MangoSSH
  • Project
  • Download
  • Guides · Connecting

    Port forwarding and jump hosts

    Carry a port you cannot reach directly over an SSH session you can, and reach servers that sit behind one or more bastions. MangoSSH does local, remote and SOCKS forwards, remembers them per host, and builds ProxyJump chains from your saved hosts.

    • SSH tunnels
    • Windows · macOS · Linux
    • About 10 minutes

    The three kinds of forward

    The only real difference is which end opens the listening port.

    KindWho listensUse it to
    Local (-L)This computerReach something only the SSH host can reach: a database on a private subnet, an admin page bound to localhost on the server.
    Remote (-R)The SSH serverLet the far side reach something only you can reach: show a local web app to someone on the server's network, or give a server access to a service on your machine.
    Dynamic SOCKS5 (-D)This computerOne local port that goes to any destination the SSH host can reach. Point a browser or tool at it as a SOCKS5 proxy.

    Where forwards live

    • The tunnel button on the session toolbar (tooltip SSH Tunneling/Port Forwarding) opens the Port Forwarding page. It lists every forward across every open SSH session as a card with a small map (you, the SSH host, the destination), live in and out rates, open and total connections, and bytes moved. A tunnel nothing has used yet says so, which tells you a problem is before the tunnel, not after it.
    • Port Forwarding in the Workspace sidebar opens a dialog with a Host picker, that host's forwards, and illustrated explanations of -L, -R and -D. Pick All hosts — every active forward to see everything at once, or Full view for the full-size map. This is also where you add a forward to a host that is not connected.

    Add a forward

    1. Connect to the SSH host that can reach the destination.

    2. Click Add forward on the Port Forwarding page, or pick the host in the Port Forwarding dialog and click Add Forward.

    3. Choose the Type and fill in the ports (see the table below), then click Create Forward.

    4. Use it. For a local forward to a database on port 5432, point your client at 127.0.0.1:5432 on your own machine.

    FieldMeaningStarts as
    TypeLocal (-L), Remote (-R) or Dynamic SOCKS5 (-D).Local
    Listen addressWhich interface the listener binds to. For local and SOCKS forwards this is on your machine; for remote forwards it is on the server.127.0.0.1; 0.0.0.0 for Remote
    Listen portThe port that accepts connections. Required.Empty
    Target hostLocal: where the SSH server connects, resolved from the server's side, so internal DNS names work. Remote: where this computer connects when traffic comes back. Hidden for SOCKS.Empty
    Target portThe port on the target host.Empty
    Keep local listeners on 127.0.0.1

    Changing a local or SOCKS listen address to 0.0.0.0 lets anyone who can reach your machine use your tunnel, and through it, everything the SSH host can reach. The SOCKS proxy has no password of its own.

    Examples

    GoalSettings
    Private PostgresLocal · listen 127.0.0.1:5432 · target db.internal:5432. Connect your client to 127.0.0.1:5432.
    Show your dev appRemote · listen 0.0.0.0:8080 · target 127.0.0.1:3000. People on the server's network open port 8080 on the server.
    Browse an internal networkDynamic · listen 127.0.0.1:1080. Set your browser's SOCKS5 proxy to 127.0.0.1:1080, or curl --socks5-hostname 127.0.0.1:1080 http://intranet/.

    A remote forward on 0.0.0.0 is only reachable from other machines if the server allows it. OpenSSH servers bind remote forwards to loopback unless GatewayPorts is enabled in sshd_config. The SOCKS proxy accepts hostnames, so DNS lookups happen on the SSH host when your client sends names rather than addresses.

    Saved forwards restart on connect

    Every forward you create with Add forward is also saved on its host. The next time that host connects, from anywhere in the app, its saved forwards start automatically. You can add a forward to a host that is not connected from the Port Forwarding dialog; the title changes to Add port forward (saves — starts on next connect).

    • Stop on a card stops the tunnel now. The saved rule stays, and the card reappears dimmed with a Start button while the host is connected, or host not connected when it is not.
    • Remove in the Port Forwarding dialog deletes the saved rule, so it no longer starts on connect.
    • Edit on a live card starts the changed forward first and only then stops the old one, so a typo leaves the original running.

    If one saved forward cannot start (its port is already in use, for example), the others still start and the connection is unaffected.

    Auto-detected dev servers

    MangoSSH watches the output of your SSH terminals for the banner a development server prints when it starts: a http://localhost:PORT, 127.0.0.1 or 0.0.0.0 URL, listening on port N, or Python's Serving HTTP on … port N. When it sees one it asks:

    Detected a dev server on port 5173 — forward it to your machine?

    Accept, and it starts a local forward from 127.0.0.1:5173 on your machine to localhost:5173 on the server, then tells you the address to open. This forward lasts for the session and is not saved on the host. It asks once per port per session, so a server that restarts in a loop does not keep prompting. It does not ask on a host where port forwarding is blocked. A bare port number in other output, such as a database connection string, does not trigger it.

    Jump hosts (ProxyJump)

    A jump host, or bastion, is a server you can reach that can reach the server you want. MangoSSH signs in to the bastion, opens a channel through it to the target, and runs a second, complete SSH connection inside that channel. The bastion relays encrypted bytes and never sees your session with the target.

    A two-hop ProxyJump chain: this computer connects to bastion 1, through it to bastion 2, and through both to the target server. This computer signs in to every hop bastion-1 public edge bastion-2 inner network db-01 the target SSH SSH inside hop 1 SSH inside hops 1–2 db-01's jump host is bastion-2 · bastion-2's jump host is bastion-1
    Each hop is a saved SSH host. Setting a jump host on a bastion is what turns one hop into a chain.

    Set up a jump host

    1. Save the bastion as an ordinary SSH host and make sure you can connect to it on its own.

    2. Open the target host with Edit and go to the Proxy tab.

    3. Under Proxy Jump (bastion), pick the bastion in Via SSH host, then Save changes.

    4. For a chain, give the bastion its own Via SSH host. MangoSSH follows the chain back to the first hop you can reach directly.

    Inherit the bastion from a group

    When every host in a group goes through the same bastion, set it once. Open Manage SSH Groups (the button next to the Group field, or the ⚙ next to the sidebar's group filter) and choose the group's Default bastion.

    • A host's own Via SSH host always wins. The group's bastion is used only when the host leaves it empty.
    • The Proxy tab shows the inherited bastion under the field, for example ↳ Inherited from group 'Production': bastion-1 — pick a bastion above to override.
    • A bastion can inherit its own jump host from its group too, so chains can be built entirely from group defaults.

    Rules worth knowing

    • Bastions cannot prompt you. Each hop signs in on its own, in the background. A password bastion needs its password saved in the OS keychain, or it fails with No saved password for bastion …. Keys, SSH Agent, PKCS#11 and Passkey sign-in all work for bastions.
    • You do not need agent forwarding for jump hosts. Your device signs in to every hop itself; no key ever has to be available on a bastion.
    • One route per host. If the host also has a ProxyCommand or an HTTP / SOCKS proxy on its Proxy tab, that route is used and the jump host is ignored.
    • Loops and long chains are refused. A chain that loops back to a bastion already in it fails with ProxyJump chain has a cycle. Chains longer than 8 hops are refused.
    • Bastion host keys are trusted on first use without a prompt. Only the final target asks you to confirm a new host key.
    • Debug mode names every hop. With Verbose / debug mode on (the default for new hosts), the connection log shows each bastion, whether it was inherited from a group, and where a failure happened.

    Agent forwarding

    Enable agent forwarding (-A), on the host's Session tab, lets SSH commands you run on the server (a git pull from a private repository, an ssh to the next machine) sign with the keys in your local ssh-agent. The keys never leave your machine; the server asks your agent to sign.

    • Windows: MangoSSH uses the OpenSSH agent service (Start-Service ssh-agent). Pageant is not supported, despite the label's mention of it.
    • macOS and Linux: SSH_AUTH_SOCK must point at a running agent. Check with ssh-add -l.
    • If no local agent is running, the session still works; programs on the server simply find no agent.
    Only forward your agent to servers you trust

    While you are connected, anyone with root on that server can ask your agent to sign as you. For hopping between machines, a jump host is the safer choice.

    X11 forwarding

    Enable X11 forwarding (-X), also on the Session tab, shows graphical Linux programs started on the server (xclock, virt-manager, wireshark) as windows on your desktop.

    • You need a local X server that accepts connections on 127.0.0.1:6000 (display :0): VcXsrv or X410 on Windows, XQuartz on macOS, or the native X server on Linux.
    • The server must allow it: X11Forwarding yes in sshd_config, and xauth installed. If it refuses, the session still connects without X11.
    • If no local X server is listening, remote programs fail to open their window; the session itself is unaffected.

    Both switches start from the defaults in Settings → Connection for new hosts. A policy can turn agent and X11 forwarding off for a group of hosts; see Policies.

    Blocking and auditing

    • Block port forwarding on this host (Session tab) refuses every local, remote and SOCKS forward on that host, including saved forwards and RDP tunnelled through it, and suppresses the dev-server prompt. A policy can set it for a whole group or tag. Like all data-copy controls it is enforced by this app; for a hard boundary use the PAM Broker.
    • Every forward that starts or stops is written to the audit log with the host, user, kind, listen address and target. See Audit, recording and alerts.

    Troubleshooting

    SymptomLikely cause
    “bind 127.0.0.1:PORT failed”Something on your machine already uses that port. Pick another listen port.
    “tcpip_forward failed” on a remote forwardThe server refused to listen: the port is taken or below 1024, or AllowTcpForwarding is off in sshd_config.
    The tunnel exists but says nothing has used itYour client is pointed somewhere else. Check the address and port it connects to.
    Traffic reaches the tunnel but the app gets no answerThe SSH host cannot reach the target. Try nc -vz TARGET PORT from a terminal on that host.
    A forward you stopped comes back after reconnectingStop leaves the saved rule in place. Remove it in the Port Forwarding dialog.
    A remote forward on 0.0.0.0 is only reachable from the server itselfThe server's GatewayPorts is off, so it bound to loopback.
    “No saved password for bastion …”Edit the bastion, enter its password with Save password to OS keychain on, or switch it to key sign-in.
    “ProxyJump chain has a cycle”Two hosts name each other as jump host, directly or through their groups. Clear one of them.
    Forwarding is refused on one host onlyPort forwarding is blocked on that host, by its own switch or a policy.