local-forward

02 — Local forward -L

Learning objectives

Intuition

-L is "bring that one internal port to my 127.0.0.1."

Friend annotation — -L in one breath

You type this on A (laptop). Listener sits on your :8080. Hitting it makes B dial their :80.

ssh -N -L 127.0.0.1:8080:127.0.0.1:80 user@B
sequenceDiagram
  participant You as A your laptop
  participant B as B bastion
  participant C as C service :80

  Note over You: Listener on A :8080
  You->>You: curl 127.0.0.1:8080
  You->>B: SSH channel (-L)
  B->>C: B dials C:80
  C-->>B: response
  B-->>You: back through SSH

Compare with -R on whiteboard / remote-forward / the SSH Tunneling handout.

Why 127.0.0.1 here is not "my laptop"

In -L …:127.0.0.1:80, that address is resolved on B. It means "B's loopback port 80," not yours. The service on the far side sees the connection from B. Port order: left = your listen port; right = what B dials. Full myth list: whiteboard FAQ / SSH Tunneling FAQ.

Practitioner

Goal: Pull one remote service to a loopback port on A.

Shape: Listener on A; real connect opened by B.

Pattern

ssh -N -o ExitOnForwardFailure=yes \
  -L 127.0.0.1:8080:INTERNAL_IP_OR_127.0.0.1:PORT \
  user@B

Demo steps

  1. Confirm what C is (lab IP/port from Academy / Poison / home lab).
  2. Start the command above; leave the terminal visible.
  3. Validate: curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080 or browser to that URL.
  4. Ask: "Who reached C?" → B.

Jump host (optional contrast)

When the need is "shell on private host," prefer jump, not a pile of -Ls:

ssh -J user@B admin@PRIVATE_HOST

Hop chain

  1. App on A → 127.0.0.1:LOCAL_PORT
  2. Listener on A (loopback)
  3. SSH → JUMPBOX:22
  4. B dials TARGET:TARGET_PORT (C’s IP, or 127.0.0.1 = B’s own loopback)
ssh -N -L 127.0.0.1:8080:TARGET_IP_OR_127.0.0.1:80 user@JUMPBOX

Checkpoint

Evidence: artifacts/evidence/02-L-check.md (command, ports, start/end, HTTP/TCP result).

Cite: [S-PC-01], [S-OSS-01].

Deep dive

Destination names in -L resolve on B, not A — surprises people when /etc/hosts differs [S-OSS-01 | high | primary].

Check

Listener up → benign hit → Ctrl-C → listener gone. Evidence file started.