# 

If you want to access some arbitrary port(s) or service(s) that are not available to the internet, you can use **port forwarding** or a **proxy**.

Both of these approaches can be accomplished using **ssh**, so as long as you can use ssh to connect to some intermediate host (sometimes called a "bastion" host) that has access to the protected resources, you can easily access them from your local machine.

```bash
SSH local port forwarding
```

-------------------------

SSH allows you to set up "local" port forwarding, which listens on a port on **your local machine** and forwards all connections to that port across the SSH tunnel to a given host and port on the remote side.

If, for example, you want to port-forward in order to access the TiDB Dashboard, you first must find the host where the Dashboard is running:

```bash
$ ssh tidb@bastion.dev.azuredatabricks.net .tiup/bin/tiup cluster display cluster-1 --dashboard
Starting component `cluster`:  display cluster-1 --dashboard
http://172.16.38.11:2379/dashboard/
```

## New SSH connection

Then execute ssh again, giving the appropriate `-L` option:

```bash
$ ssh -L1337:172.16.38.11:2379 tidb@bastion.dev.azuredatabricks.net
[tidb@tiup ~]$
```

In this case, I am forwarding port **1337** to port **2379** of **172.16.38.11**. Now, I can load **<http://localhost:1337/dashboard/>** in my browser to view the Dashboard, or I can use curl on the command line (of your local machine!) to confirm that the forwarding works as expected:

```bash
$ curl http://localhost:2379/dashboard/
<!doctype html><html><head><meta charset="utf-8"/><meta name="x-public-path-prefix" content="/dashboard"/>…
```

## Existing SSH connection

If you're already connected to the remote host via ssh and you don't want to re-connect to set up port forwarding, you can set it up on the SSH console of an existing connection.

To open the SSH command line, use these steps:

1. Hit the <enter> key
    Type a `~` (tilde) character
2. Type a `C` (upper-case c) character
    You should see a `ssh>`  prompt

At the `ssh>`  prompt, you're going to use the exact same `-L` construction you would've used in the step above if you were creating a new SSH connection. For example:

```bash
$ ssh tidb@bastion.dev.azuredatabricks.net
[tidb@tiup ~]$ tiup cluster display cluster-1 --dashboard
Starting component `cluster`:  display cluster-1 --dashboard
http://172.16.38.11:2379/dashboard/
[tidb@tiup ~]$
[tidb@tiup ~]$
ssh> -L1337:172.16.38.11:2379
Forwarding port.

[tidb@tiup ~]$
```

You may have to hit <enter> to get back to your shell prompt.

## Reference

For reference, here's the description of local port forwarding from the SSH man page:

```bash
-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket
        Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host
        and port, or Unix socket, on the remote side.  This works by allocating a socket to listen to either a TCP port on the local
        side, optionally bound to the specified bind_address, or to a Unix socket.  Whenever a connection is made to the local port or
        socket, the connection is forwarded over the secure channel, and a connection is made to either host port hostport, or the Unix
        socket remote_socket, from the remote machine.

        Port forwardings can also be specified in the configuration file.  Only the superuser can forward privileged ports.  IPv6
        addresses can be specified by enclosing the address in square brackets.

        By default, the local port is bound in accordance with the GatewayPorts setting.  However, an explicit bind_address may be used
        to bind the connection to a specific address.  The bind_address of ``localhost'' indicates that the listening port be bound for
        local use only, while an empty address or `*' indicates that the port should be available from all interfaces.
```

SSH dynamic port forwarding (SOCKS proxy)

-----------------------------------------

If you don't know which host you are going to want to forward to, or if you may want to access multiple services (such as Grafana as well as the TiDB Dashboard and maybe some API endpoints), you can use SSH "dynamic" port forward to set up a **SOCKS proxy**.

```bash
Simply choose a **local** port that's unused and give that as an argument to SSH's -D option:

$ ssh **-D1337** tidb@bastion.dev.azuredatabricks.net
[tidb@tiup ~]$ tiup cluster display cluster-1
Starting component `cluster`:  display cluster-1
tidb Cluster: cluster-1
tidb Version: v4.0.5
ID                  Role          Host          Ports        OS/Arch       Status   Data Dir                         Deploy Dir
--                  ----          ----          -----        -------       ------   --------                         ----------
172.16.38.5:9093    alertmanager  172.16.38.5   9093/9094    linux/x86_64  Up       /data/tidb-data/alertmanager     /data/tidb-deploy/alertmanager
172.16.38.5:3000    grafana       172.16.38.5   3000         linux/x86_64  Up       -                                /data/tidb/tidb-deploy/grafana
172.16.38.11:2379   pd            172.16.38.11  2379/2380    linux/x86_64  Up|L|UI  /data/tidb/tidb-data/pd          /data/tidb/tidb-deploy/pd
172.16.38.12:2379   pd            172.16.38.12  2379/2380    linux/x86_64  Up       /data/tidb/tidb-data/pd          /data/tidb/tidb-deploy/pd
172.16.38.13:2379   pd            172.16.38.13  2379/2380    linux/x86_64  Up       /data/tidb/tidb-data/pd          /data/tidb/tidb-deploy/pd
172.16.38.5:9090    prometheus    172.16.38.5   9090         linux/x86_64  Up       /data/tidb/tidb-data/prometheus  /data/tidb/tidb-deploy/prometheus
172.16.38.11:4000   tidb          172.16.38.11  4000/10080   linux/x86_64  Up       -                                /data/tidb/tidb-deploy/tidb
172.16.38.12:4000   tidb          172.16.38.12  4000/10080   linux/x86_64  Up       -                                /data/tidb/tidb-deploy/tidb
172.16.38.13:4000   tidb          172.16.38.13  4000/10080   linux/x86_64  Up       -                                /data/tidb/tidb-deploy/tidb
172.16.38.14:4000   tidb          172.16.38.14  4000/10080   linux/x86_64  Up       -                                /data/tidb/tidb-deploy/tidb
172.16.38.10:20160  tikv          172.16.38.10  20160/20180  linux/x86_64  Up       /data/tidb/tidb-data/tikv        /data/tidb/tidb-deploy/tikv
172.16.38.4:20160   tikv          172.16.38.4   20160/20180  linux/x86_64  Up       /data/tidb/tidb-data/tikv        /data/tidb/tidb-deploy/tikv
172.16.38.6:20160   tikv          172.16.38.6   20160/20180  linux/x86_64  Up       /data/tidb/tidb-data/tikv        /data/tidb/tidb-deploy/tikv
172.16.38.7:20160   tikv          172.16.38.7   20160/20180  linux/x86_64  Up       /data/tidb/tidb-data/tikv        /data/tidb/tidb-deploy/tikv
172.16.38.8:20160   tikv          172.16.38.8   20160/20180  linux/x86_64  Up       /data/tidb/tidb-data/tikv        /data/tidb/tidb-deploy/tikv
172.16.38.9:20160   tikv          172.16.38.9   20160/20180  linux/x86_64  Up       /data/tidb/tidb-data/tikv        /data/tidb/tidb-deploy/tikv
```

## From command line

Now, on your local host, you can connect to port 1337 using any application or tool that can connect via a SOCKS proxy. That includes any web browser or command-line tools such as curl.

```bash
$ curl -x socks5://localhost:1337 **http://172.16.38.11:2379**/dashboard/  
<!doctype html><html><head><meta charset="utf-8"/><meta name="x-public-path-prefix" content="/dashboard"/>  
…
```

```bash
$ curl -x socks5://localhost:1337 **http://172.16.38.5:3000**/login/  
<!DOCTYPE html>  
<html lang="en">  
  
<head>  
<meta charset="utf-8">  
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">  
<meta name="viewport" content="width=device-width">  
<meta name="theme-color" content="#000">  
  
<title>Grafana</title>  
…
```

```bash
$ curl -x socks5://localhost:1337 http://172.16.38.5:9090/graph  
<!DOCTYPE html>  
<html lang="en">  
<head>  
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
<meta name="robots" content="noindex,nofollow">  
<title>Prometheus Time Series Collection and Processing Server</title>  
…
```

## In web browser

Web browser configuration for proxies varies. At least on macOS, Google Chrome and Safari both want to use the _operating s__ystem_ setting for the proxy. It's **not advisable** to have all your web traffic go through the proxy, especially when it's a customer system. For that reason...

**You should use Firefox** or another web browser that supports its own proxy configuration rather than relying on the operating system proxy settings.

In Firefox preferences (about:preferences), find General -> Network Settings and click "Settings", or search for "proxy" in the "Find in Preferences" search bar.

Choose "**Manual proxy configuration**", set **SOCKS Host** to "localhost", and set **Port** to the port you used in SSH's -D option.

If you want to be able to use hostnames that only resolve on an internal network, you should scroll down and enable "**Proxy DNS when using SOCKS v5**".

If you need to be able to access services running on **127.0.0.1**, i.e. services bound _only_ to the loopback network interface of the host you SSH to, you must enable an additional setting in Firefox. Load "about:config" and navigate past its dire warnings about your safety and security. Search for the preference named "**network.proxy.allow_hijacking_localhost**". Change the value to true. (Normally, Firefox doesn't want to hijack connections to 127.0.0.1/localhost because I suppose there could be some impersonation security issue if some nefarious website pretended to be a local service and asked you for passwords, I'm not really sure.)

![Screen_Shot_2020-09-15_at_12.39.34_PM.png](/hc/article_attachments/360091543233/Screen_Shot_2020-09-15_at_12.39.34_PM.png)

After you've set up SOCKS in the browser, you can directly load resources on internal IP addresses:

![Screen_Shot_2020-09-15_at_12.48.52_PM.png](/hc/article_attachments/360091545473/Screen_Shot_2020-09-15_at_12.48.52_PM.png)

### Reference

From the SSH man page:

```bash
-D [bind_address:]port
        Specifies a local ``dynamic'' application-level port forwarding.  This works by allocating a socket to listen to port on the
        local side, optionally bound to the specified bind_address.  Whenever a connection is made to this port, the connection is for-
        warded over the secure channel, and the application protocol is then used to determine where to connect to from the remote
        machine.  Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server.  Only root can forward
        privileged ports.  Dynamic port forwardings can also be specified in the configuration file.
```