SSH Proxy — Manual
Full reference for SSH Proxy: all ten generators, Bash and PowerShell output, auto-reconnect, input warnings, the help tabs and the architecture.
Back to overview: SSH Proxy · Open the live tool: www.jpkc.com/tools/ssh-proxy/
This manual describes SSH Proxy in full: how the interface is laid out, what each of the ten generators does, which options exist, and what is actually produced. The tool's interface is in English, so labels appear here exactly as you'll find them on screen.
Layout and operation
On the left is a navigation bar with ten entries, grouped into Port Forwarding, Configuration, Scripts & Automation and Help. On the right, the selected entry shows a card with input fields and, below it, the output pane — a read-only ACE editor (opens in a new tab) with syntax highlighting to match the output (Bash, PowerShell or XML, for instance).
Three paths lead to output:
- The Generate button in the top right of the input card produces the result and scrolls to the output.
- The tool also regenerates automatically as soon as you change a field (after a 300 ms pause) and whenever you switch tabs. When the page opens, the editor already holds a sample Local Forward command.
- Above the output sit Copy (to the clipboard) and Download (as a file, with a fitting name such as
local-forward.sh,local-forward.ps1orssh-config).
The four tunnel generators (Local, Remote, Dynamic, Jump Host) also show an Explanation table below the output that explains each generated flag (column Flag) in plain language (column Meaning). Lists with multiple forwards, jump hosts or tunnel definitions grow with Add … and shrink with the red ×; the last row can't be removed (At least one row is required.). On a phone, these tables turn into labelled blocks stacked on top of each other.
Almost every generator checks your input and lists warnings at the foot of the output card — the command is still generated, but you see where it will trip. Examples: a port outside 1 to 65535, a host name with invalid characters, a local port below 1024 (needs root on Linux/macOS), a bind address other than loopback that opens the port to other machines, or ForwardAgent in the SSH config.
The tool stores nothing. Reload the page and the fields are back to their defaults.
Shared SSH options
The three pure tunnel generators (Local/Remote/Dynamic) share a set of fields and switches. How they affect the command:
- OS — Linux, macOS, Windows (OpenSSH), BSD or WSL. Your choice determines the output format, see Output per operating system.
- SSH Host / SSH Port / SSH User — the connection target. Empty fields are replaced with placeholders (
server.example.com,user). A port other than 22 adds-p <port>; an invalid port triggers a warning and the command falls back to 22. - Identity File (optional) — the path to the private key; adds
-i <path>. Paths with spaces are quoted correctly, while a leading~/stays unquoted so the shell can expand it. Only the path is recorded, never the key itself. - Background
-f -N(on by default) — sends SSH to the background after authentication (-f), runs no remote command (-N, tunnel only) and adds-o ExitOnForwardFailure=yes: if a port can't be bound,sshexits instead of carrying on without the forward. On Windows-fis dropped (see below). With the switch off you get an ordinary login with forwarding. - Compression
-C— enables compression (useful on slow links). - KeepAlive (60s) (on by default) — adds
-o ServerAliveInterval=60 -o ServerAliveCountMax=3so dropped connections are detected.
Output per operating system
For Linux, macOS, BSD and WSL the tool emits a Bash script: shebang #!/usr/bin/env bash, an explanatory comment and the command wrapped across line continuations (\). The download ends in .sh.
For Windows (OpenSSH) you get a PowerShell script (.ps1) for the ssh.exe that ships with Windows 10/11: backticks as line continuations, quoting by PowerShell rules. Since Windows OpenSSH has no -f, the script starts the tunnel hidden in the background when Background is on:
$tunnel = Start-Process -WindowStyle Hidden -PassThru -FilePath ssh -ArgumentList @(
'-L',
'127.0.0.1:3306:127.0.0.1:3306',
…
)
Write-Host "Tunnel running, PID $($tunnel.Id) - stop with: Stop-Process -Id $($tunnel.Id)"On every platform, IPv6 addresses in forwards are put in square brackets automatically (-L '[::1]:8080:[fd00::5]:80') — without them ssh complains about a "Bad forwarding specification".
Auto-reconnect
All three tunnel generators have an Auto-Reconnect switch. When it's on, two extra fields appear — Reconnect Method and Retry Delay (s) (default 5, minimum 1):
- autossh (recommended) — replaces
sshwithautossh -M 0and setsexport AUTOSSH_GATETIME=0, so autossh keeps trying even if the very first connection fails. A comment gives the install command for the chosen OS (apt/dnf,brew,pkg).autosshis a separate program (not part of OpenSSH) that monitors the connection and rebuilds it after a drop;-M 0disables the legacy monitoring port and relies on the KeepAlive options instead — if KeepAlive is off, the tool warns you. - while loop (no dependency) — wraps the command in a loop that restarts
ssh<delay>seconds after every exit and logs the drop with a timestamp. The tool removes-f, because the loop has to seesshexit, and adds-NandExitOnForwardFailure=yesif they're missing. In Bash that'swhile true; do … sleep <delay>; done(with a hint to detach the script from the terminal vianohup); on Windows it'swhile ($true) { … Start-Sleep -Seconds <delay> }.
There's no autossh on Windows: pick autossh there and the tool generates the PowerShell loop instead, saying so in a note.
The generators in detail
Local Forward (ssh -L)
Forwards a port on your local machine through the SSH server to a remote service. Typical case: reaching a database or web service behind a firewall.
In the Port Forwards table you define one forward per row with Local Bind (default 127.0.0.1), Local Port (default 3306), Remote Host (127.0.0.1) and Remote Port (3306). Each row becomes -L bind:lport:rhost:rport; an empty bind leaves that part out. Multiple rows (Add Port) produce multiple -L flags in a single invocation. The Remote Host is resolved from the SSH server's point of view — so 127.0.0.1 is the server itself.
Warnings cover ports outside 1 to 65535, local ports below 1024 (except on Windows) and a bind address other than loopback, which makes the port reachable from other machines.
Remote Forward (ssh -R)
Exposes a local service on the remote server (the reverse direction). Typical case: letting a remote server reach your local dev environment, or testing webhooks.
The table has Remote Bind (empty by default — placeholder server loopback), Remote Port (8080), Local Host (127.0.0.1) and Local Port (3000); each row becomes -R [bind:]rport:lhost:lport. Without a bind, the port listens only on the server's loopback interface.
If the port should be publicly reachable on the server, tick Public on the server (GatewayPorts). With the switch ticked, the tool adds a comment block — the server needs GatewayPorts clientspecified in /etc/ssh/sshd_config, followed by sudo systemctl reload ssh (sshd on RHEL/Fedora), and the port belongs behind a firewall — plus a warning that the port is open on every interface of the server. If the bind is left empty, it also fills in 0.0.0.0. Enter a public bind without ticking the switch and the tool warns that the server will ignore it and listen on loopback only. A remote port below 1024 only works if you log in to the server as root — there's a note for that too.
Dynamic / SOCKS (ssh -D)
Builds a SOCKS5 proxy tunnel. All traffic an application sends through this proxy exits at the SSH server — like a lightweight VPN. Fields: Bind Address (default 127.0.0.1) and SOCKS Port (1080); these become -D bind:port. A bind other than loopback turns it into an open proxy for anyone who can reach your machine — the tool warns you about that.
The output ends with a commented-out test line, # curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.me, to check that the tunnel is up; --socks5-hostname sends DNS resolution through the server as well. An info box in the form points to the Proxy Settings generator for switching applications over to the proxy.
Jump Host (ssh -J)
Connects through one or more bastion / jump hosts to a target. Fields: OS, Mode, Identity File (optional) and the switches Compression -C and KeepAlive. In the Jump Chain table you enter the hops in order (host, port, user; Add Jump appends numbered rows); below come Final Destination Host, Destination Port and Destination User.
The Mode field selects:
- Modern (-J / ProxyJump) — produces
ssh -J user@jump[:port],…plus optional-C, KeepAlive and-pfor a destination port other than 22. IPv6 hops go in square brackets. Requires OpenSSH 7.3 or newer. If an Identity File is set, the tool putsssh-add <key>in front of the command: with-J,-ionly applies to the destination, and the jump hosts take the key from the SSH agent. On Windows a note reminds you that this needs the OpenSSH Authentication Agent service running (Start-Service ssh-agent). - Legacy (ProxyCommand) — for exactly one jump host, a command with
-o 'ProxyCommand=ssh -W %h:%p … jumpuser@jumphost'(the jump host's port and key live in the innerssh); for multiple jumps the tool emits chained~/.ssh/configblocksjump1…jumpNandtargetinstead, which you then use withssh target. In that case the download is namedssh-config.
SSH Config (~/.ssh/config)
Produces a ready-made Host block to append to ~/.ssh/config (on Windows %USERPROFILE%\.ssh\config). Fields are Host Alias (the short name you later connect with via ssh <alias>; spaces are replaced with hyphens and trigger a warning), HostName, Port (only written to the block if it isn't 22), User, optional IdentityFile and ProxyJump, plus ServerAliveInterval (60) and ServerAliveCountMax (3). Values containing spaces are wrapped in quotes.
Switches add directives:
- Compression →
Compression yes - ExitOnForwardFailure yes (on by default)
- Trust new host keys automatically →
StrictHostKeyChecking accept-new: an unknown server key is stored on first contact, but a changed key is still rejected. - ControlMaster auto — reveals ControlPath (default
~/.ssh/sockets/%r@%h-%p) and ControlPersist (600). A comment above the block reminds you to create the socket directory (mkdir -p ~/.ssh/sockets && chmod 700 ~/.ssh/sockets) and notes that Windows OpenSSH doesn't support connection sharing. - AddKeysToAgent yes, IdentitiesOnly yes
- ForwardAgent yes (flagged as a security risk) — the output adds a comment line, and the warning below explains that root on the destination server can use your keys while you're connected.
The optional ConnectTimeout and ConnectionAttempts fields only end up in the block if you enter a number.
The Port Forwards table starts out empty; Add Forward creates rows made of Type (Local/Remote/Dynamic), Bind:Port and Target:Port. These become LocalForward, RemoteForward or DynamicForward (the last needs only Bind:Port). Rows without Bind:Port are skipped; a LocalForward/RemoteForward without a target triggers a warning. The block ends with # Usage: ssh <alias> together with the check command ssh -G <alias>, which prints the values ssh actually takes from your config.
Proxy Settings
Produces configuration commands to point your tools at a proxy — typically after setting up a SOCKS tunnel with ssh -D. At the top you choose Proxy Type (SOCKS5/HTTP/HTTPS), Proxy Host (127.0.0.1) and Proxy Port (1080).
With SOCKS5, the tool writes proxy URLs as socks5h://host:port: the h means name resolution goes through the tunnel as well — internal host names work, and DNS queries don't leak around the proxy. That applies to the shell variables, git, npm, apt, dnf, pip and cargo. Go, Docker and kubectl get socks5://, because Go programs send host names to the SOCKS server anyway.
Under NO_PROXY Exclusions you set exceptions: localhost / 127.0.0.1 (on; becomes localhost,127.0.0.1,::1), Private ranges (as CIDR 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16), Link-local (169.254.0.0/16) and your own entries in the text field, one per line or comma-separated (e.g. .example.com). For Java tools (Gradle, Maven) and the Windows bypass list, the tool converts CIDR ranges into the wildcards those programs understand (10.*, 172.16.* … 172.31.*) and turns .example.com into *.example.com.
In the Generate Configuration For block you tick which configurations should appear — grouped into four cards:
- Shell & System
- Shell env vars (on) —
exportofALL_PROXY,HTTP_PROXY,HTTPS_PROXY(plus lowercase) andNO_PROXYfor~/.bashrc,~/.zshrcor~/.profile, with anunsetline to undo it. - macOS (networksetup) — SOCKS or web/secure-web proxy and bypass domains for the
"Wi-Fi"service (with a hint on how to find your service name). - Windows (netsh / PowerShell) — user environment variables via
[Environment]::SetEnvironmentVariable(…, "User"); for HTTP/HTTPS alsonetsh winhttp set proxywith a bypass list for system services. WinHTTP can't do SOCKS — with SOCKS5 you get a note there instead. - Linux Desktop (gsettings) — the GNOME system proxy including
ignore-hostsand a reset command.
- Shell env vars (on) —
- Dev Tools
- git —
git config --global http.proxyplus an exception for individual servers and--unset. - npm —
proxy,https-proxy,noproxyandconfig delete. - Gradle / Android Studio —
systemProplines for~/.gradle/gradle.properties(SOCKS or HTTP/HTTPS,nonProxyHostswith|) and the menu path in Android Studio. - Maven — a
<proxy>block for~/.m2/settings.xml; since Maven proxies only speak HTTP, SOCKS gets aMAVEN_OPTSline instead.
- git —
- Package Managers
- apt — the file
/etc/apt/apt.conf.d/95proxyviatee, with a command to remove it. - yum / dnf — a
proxy=line in/etc/dnf/dnf.conf(or/etc/yum.conf), with asedcommand to remove it. - Docker — a systemd drop-in
/etc/systemd/system/docker.service.d/proxy.conffor the daemon (image pulls) includingdaemon-reloadand a restart, plus the JSON snippet for~/.docker/config.json(containers and builds). For SOCKS, a note that127.0.0.1inside a container is the container itself. - curl / wget — an invocation and a
~/.curlrcline;wgetcan't do SOCKS, so the tool suggestsproxychains4. - pip / poetry —
pip install --proxy, apip.confline, and for SOCKS a pointer to PySocks. - Composer (PHP), cargo (Rust), go — the matching environment variables (Composer: check with
composer diagnose; cargo:CARGO_HTTP_PROXYor~/.cargo/config.toml).
- apt — the file
- Cloud CLIs
- kubectl —
HTTPS_PROXY/NO_PROXYand the alternativeproxy-urlper cluster in~/.kube/config. - AWS CLI — environment variables; for SOCKS a note that the AWS CLI can't do SOCKS.
- gcloud (GCP) —
gcloud config set proxy/type|address|portincludingunset. - Azure CLI —
HTTPS_PROXYand a note onREQUESTS_CA_BUNDLEbehind TLS-inspecting proxies.
- kubectl —
The output strings the selected sections together with separator lines; where there's a clear way back, the removal command sits right alongside. With nothing ticked, all you see is # Select at least one section above.. The download is named proxy-settings.sh.
Management Script
Produces a management script for several tunnels. Fields: Script Type (Bash or PowerShell), Script Name (tunnel-manager; special characters are replaced, and it also sets the download name .sh/.ps1), PID Directory (/tmp/ssh-tunnels). Switches: Auto-reconnect (on, reveals Reconnect Interval (seconds) — default 30, minimum 5), Logging (on, reveals Log Path — default ~/.local/state/ssh-tunnels; for paths under /var/log the tool warns, with Script Type Bash, that usually only root may write there) and Health check.
In the Tunnel Definitions table you describe each tunnel with Name, Type (Local/Remote/Dynamic), SSH Host, User, Port, Forward (for -L: [bind:]localPort:targetHost:targetPort, for -R: [bind:]serverPort:localHost:localPort; for -D: just the port, 1080 if empty) and an optional Key. The Forward field goes to ssh -L/-R/-D unchanged: the tool's tooltip gives localPort:remoteHost:remotePort for both directions, but with -R the first port is the one on the server. Duplicate names are renamed and reported; empty fields are filled with placeholders.
Every tunnel starts as ssh -N with fixed options: BatchMode=yes (never wait for a password prompt — accept the host key once by hand beforehand), ExitOnForwardFailure=yes and KeepAlive (60 s/3). The script keeps one PID file per tunnel.
- Bash (bash 3.2+, so it also runs on the macOS Bash; Linux/macOS/BSD/WSL): call it as
./tunnel-manager.sh {start|stop|restart|status|list} [name]—start,stop,restartandstatustake the optional name and apply to all tunnels without one;list,watchandhealthalways cover all tunnels. Auto-reconnect addswatch(checks every Reconnect Interval seconds and restarts dead tunnels; stop it with Ctrl+C), Health check addshealth(usesnc -zto test whether the local port of each Local/Dynamic tunnel accepts connections; Remote tunnels listen on the server and are skipped).startreports after one second whether the tunnel is really up; with Logging, each tunnel's output goes to<Log Path>/<name>.log. - PowerShell (5.1+, Windows OpenSSH): call it as
.\tunnel-manager.ps1 start|stop|restart|status|list [-TunnelName name], pluswatchwith Auto-reconnect;-TunnelNameapplies to every action exceptlist, which always shows all tunnels. Tunnels run hidden viaStart-Process. A Unix-style PID or log path (starting with/) is created under$env:TEMP. Health check only takes effect in the Bash variant.
Autostart Setup
Produces an autostart configuration that starts a single tunnel at boot or at logon. Fields are Autostart Method, SSH Host/Port/User, Identity File, Tunnel Type (Local/Remote/Dynamic), Forward Spec (empty means 3306:127.0.0.1:3306 — even for Dynamic; for -D, enter the port yourself, e.g. 1080), Service Name (ssh-tunnel), Run as User (empty, example alice; applies to systemd and rc.d) and Description (SSH Tunnel Service).
The underlying invocation is built the same way on every system: ssh -N -o BatchMode=yes -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -L <spec> [-p <port>] [-i <key>] user@host (with -R or -D instead of -L, depending on Tunnel Type). Because services run without a terminal, the tool always reminds you to accept the host key once by hand (ssh user@host) and to use a key without a passphrase or an agent.
The output has two tabs: the start script tunnel.sh (exec ssh …; with Task Scheduler you get a PowerShell script instead, downloaded as tunnel.ps1) and the configuration file, whose tab label follows the chosen method. Copy and Download act on whichever tab is visible. The Autostart Method field selects the mechanism:
- systemd (Linux) —
<Service Name>.servicewith install instructions in the comments (sudo cp …,daemon-reload,enable --now,journalctl -u … -f),After=/Wants=network-online.target,StartLimitIntervalSec=0,Restart=alwaysandRestartSec=10. Without Run as User there's noUser=line; the service would then run as root with/root/.ssh— the tool warns you. - launchd (macOS) —
com.user.<Service Name>.plistfor~/Library/LaunchAgents/withRunAtLoad,KeepAlive,ThrottleInterval10 and an error log at/tmp/<Service Name>.err; load it withlaunchctl bootstrap gui/$(id -u) …, unload it withlaunchctl bootout. - Task Scheduler (Windows) —
<Service Name>.xmlwith a logon trigger, no admin rights, no run-time limit, allowed on battery power, and restart on failure (every minute, up to 999 times); it runsC:\Windows\System32\OpenSSH\ssh.exe. The download is saved as UTF-16 with BOM and Windows line endings, just as the XML declaration demands; import it withschtasks /create /tn "<name>" /xml <name>.xml. - rc.d (BSD) — an rc script that starts
sshviadaemon(8)and restarts it when it dies (-r), with install commands (install -m 755,sysrc <name>_enable=YES,service <name> start) and an optional<name>_user. - crontab @reboot (WSL/generic) — an
@rebootentry forcrontab -e, plus a variant for~/.bashrc/~/.profilethat starts the tunnel vianohupunlesspgrep -f -- '-L <spec>'already finds it (WSL doesn't start cron on its own).
The help tabs
Troubleshooting
A browseable guide to eleven common SSH problems as an accordion — from Connection refused, Permission denied (publickey), Port already in use and Host key verification failed, through Broken pipe, Channel open failed and SOCKS proxy not working, to autossh, SSH agent problems, DNS through SOCKS and reconnection strategies on network changes.
In the top right you pick the OS (Linux/macOS/Windows/BSD/WSL); for each problem the tool then shows the matching diagnostic commands (each with its own copy button) and a list of concrete solutions. This tab generates nothing — it presents ready knowledge.
Reference
A collection of lookup tables, also without generation: a comparison table of the forward types (-L/-R/-D/-J), data-flow diagrams for each type, a table of common SSH flags, Do/Don't security lists, example scenarios, a guide to key generation (Ed25519 vs. RSA with a comparison table), a section on connection multiplexing (ControlMaster), and a comparison of SSH tunnels vs. alternatives (WireGuard, ngrok / Cloudflare Tunnel, AWS SSM, Teleport, Tailscale / ZeroTier).
Architecture and limits
- Fully client-side: SSH Proxy is pure JavaScript (jQuery, the ACE editor and a module of its own for quoting and input checks). There is no server backend, no API and no SSH connection — the tool only produces text. Your inputs (hosts, users, paths) don't leave the browser and aren't stored.
- No keys in the tool: you only supply the path to an identity file, never the key itself.
- Quoting for every target format: the same input is escaped to suit each output — for Bash, PowerShell,
ssh_config, systemdExecStart, XML (launchd, Task Scheduler) and Windows command lines. A space in a key path no longer turns into a bogus host name. - Running is up to you: commands and scripts are a starting point. Review and test them in a safe environment before using them in production — misconfigured tunnels can expose internal services. The disclaimer at the foot of the page says as much.
For the introduction and target audiences, see the overview page. Concrete walkthroughs are in the examples, strategy and pitfalls in the tips & tricks. You can try it all directly in the tool.