diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
index b59a0bc48..4f6c621c0 100644
--- a/docs/.vuepress/config.js
+++ b/docs/.vuepress/config.js
@@ -5,11 +5,8 @@ module.exports = {
"Pomerium is a beyond-corp inspired, zero trust, open source identity-aware access proxy.",
plugins: [
"vuepress-plugin-element-tabs",
- 'vuepress-plugin-mermaidjs',
- [
- 'vuepress-plugin-code-copy',
- true
- ],
+ "vuepress-plugin-mermaidjs",
+ ["vuepress-plugin-code-copy", true],
[
"check-md",
{
@@ -32,14 +29,15 @@ module.exports = {
],
markdown: {
externalLinkSymbol: false,
- extendMarkdown:(md) => {
- md.use(require('markdown-it-include'), {
- root: './docs/partials/'
- })
+ extendMarkdown: (md) => {
+ md.use(require("markdown-it-include"), {
+ root: "./docs/partials/",
+ });
},
},
themeConfig: {
home: false,
+ activeHeaderLinks: false,
logo: "/img/logo_white.svg",
repo: "pomerium/pomerium",
editLinks: true,
@@ -117,6 +115,7 @@ module.exports = {
path: "/docs/identity-providers/",
type: "group",
sidebarDepth: 0,
+ initialOpenGroupIndex: 0,
children: [
"identity-providers/",
"identity-providers/auth0",
@@ -130,13 +129,29 @@ module.exports = {
"identity-providers/ping",
],
},
- "client",
+ {
+ title: "TCP Connections",
+ collapsable: false,
+ path: "/docs/tcp/",
+ type: "group",
+ sidebarDepth: 1,
+ children: [
+ "tcp/",
+ "tcp/client",
+ {
+ title: "Examples",
+ collapsable: true,
+ type: "group",
+ sidebarDepth: 0,
+ children: ["tcp/mysql", "tcp/rdp", "tcp/redis", "tcp/ssh"],
+ },
+ ],
+ },
{
title: "Topics",
- collapsable: true,
+ collapsable: false,
path: "/docs/topics/",
type: "group",
- collapsable: false,
sidebarDepth: 1,
children: [
"topics/certificates",
@@ -146,7 +161,6 @@ module.exports = {
"topics/kubernetes-integration",
"topics/production-deployment",
"topics/programmatic-access",
- "topics/tcp-support",
"topics/single-sign-out",
"topics/load-balancing",
],
@@ -238,7 +252,7 @@ module.exports = {
},
"api",
"upgrading",
- "changelog"
+ "changelog",
],
},
],
@@ -246,7 +260,8 @@ module.exports = {
},
head: [
//Hack: Make clicking on the logo go to home url
- ["script",
+ [
+ "script",
{},
`
const logoUrlChanger = setInterval(function() {
@@ -268,7 +283,7 @@ module.exports = {
}
}, 1000)
- `
- ]
+ `,
+ ],
],
};
diff --git a/docs/.vuepress/public/_redirects b/docs/.vuepress/public/_redirects
index 2ce952327..0f1bf72fe 100644
--- a/docs/.vuepress/public/_redirects
+++ b/docs/.vuepress/public/_redirects
@@ -65,3 +65,6 @@
/docs/quick-start/helm.html /docs/install/helm.html
/docs/quick-start/from-source.html /docs/install/from-source.html
/docs/quick-start/synology.html /docs/guides/synology.html
+
+/docs/client.html /docs/tcp/client.html
+/docs/topics/tcp-support.html /docs/tcp/
\ No newline at end of file
diff --git a/docs/.vuepress/theme/layouts/Draft.vue b/docs/.vuepress/theme/layouts/Draft.vue
new file mode 100644
index 000000000..4a69fec24
--- /dev/null
+++ b/docs/.vuepress/theme/layouts/Draft.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/docs/docs/img/desktop/new-ssh-connection.png b/docs/docs/img/desktop/new-ssh-connection.png
deleted file mode 100644
index 88082789c..000000000
Binary files a/docs/docs/img/desktop/new-ssh-connection.png and /dev/null differ
diff --git a/docs/docs/img/tcp-ssh-route.png b/docs/docs/img/tcp-ssh-route.png
deleted file mode 100644
index db5e4be30..000000000
Binary files a/docs/docs/img/tcp-ssh-route.png and /dev/null differ
diff --git a/docs/docs/client.md b/docs/docs/tcp/client.md
similarity index 97%
rename from docs/docs/client.md
rename to docs/docs/tcp/client.md
index a1fe52437..46392c739 100644
--- a/docs/docs/client.md
+++ b/docs/docs/tcp/client.md
@@ -38,6 +38,8 @@ The example below demonstrates a route to the SSH service on the host running th
::::
:::::
+See the "Configure Routes" section of [TCP Support](/docs/tcp/readme.md#configure-routes) for more detailed information on TCP routes.
+
## TCP Client Software
You can connect to this route with either the Pomerium CLI or Pomerium Desktop client.
@@ -126,7 +128,7 @@ See [Release](/docs/releases.md#pomerium-cli) to learn how to install pomerium-c
::::
:::::
-For more examples and detailed usage information, see [TCP Support](/docs/topics/tcp-support.md)
+For more examples and detailed usage information, see [TCP Support](/docs/tcp/readme.md)
## Advanced Configuration
@@ -136,4 +138,4 @@ If Pomerium is listening on a port other than `443` (set with the [`address` key
pomerium-cli tcp ssh.localhost:pomerium.io:2222 \
--pomerium-url https://ssh.localhost.pomerium.io:8443 \
--listen :2222
-```
\ No newline at end of file
+```
diff --git a/docs/docs/tcp/img/desktop/example-mysql-connection.png b/docs/docs/tcp/img/desktop/example-mysql-connection.png
new file mode 100644
index 000000000..44b37363b
Binary files /dev/null and b/docs/docs/tcp/img/desktop/example-mysql-connection.png differ
diff --git a/docs/docs/tcp/img/desktop/example-rdp-connection.png b/docs/docs/tcp/img/desktop/example-rdp-connection.png
new file mode 100644
index 000000000..b140df34e
Binary files /dev/null and b/docs/docs/tcp/img/desktop/example-rdp-connection.png differ
diff --git a/docs/docs/tcp/img/desktop/example-redis-connection.png b/docs/docs/tcp/img/desktop/example-redis-connection.png
new file mode 100644
index 000000000..9801ba477
Binary files /dev/null and b/docs/docs/tcp/img/desktop/example-redis-connection.png differ
diff --git a/docs/docs/tcp/img/desktop/example-ssh-connection.png b/docs/docs/tcp/img/desktop/example-ssh-connection.png
new file mode 100644
index 000000000..24a867b77
Binary files /dev/null and b/docs/docs/tcp/img/desktop/example-ssh-connection.png differ
diff --git a/docs/docs/tcp/img/desktop/new-ssh-connection.png b/docs/docs/tcp/img/desktop/new-ssh-connection.png
new file mode 100644
index 000000000..85ec26998
Binary files /dev/null and b/docs/docs/tcp/img/desktop/new-ssh-connection.png differ
diff --git a/docs/docs/tcp/img/remmina-connection-profile.png b/docs/docs/tcp/img/remmina-connection-profile.png
new file mode 100644
index 000000000..ef520d461
Binary files /dev/null and b/docs/docs/tcp/img/remmina-connection-profile.png differ
diff --git a/docs/docs/tcp/img/remmina-connection-scripted.png b/docs/docs/tcp/img/remmina-connection-scripted.png
new file mode 100644
index 000000000..53febcae3
Binary files /dev/null and b/docs/docs/tcp/img/remmina-connection-scripted.png differ
diff --git a/docs/docs/tcp/img/tcp-ssh-route.png b/docs/docs/tcp/img/tcp-ssh-route.png
new file mode 100644
index 000000000..88562a3a3
Binary files /dev/null and b/docs/docs/tcp/img/tcp-ssh-route.png differ
diff --git a/docs/docs/tcp/mysql.md b/docs/docs/tcp/mysql.md
new file mode 100644
index 000000000..a2e12c0e7
--- /dev/null
+++ b/docs/docs/tcp/mysql.md
@@ -0,0 +1,70 @@
+---
+title: MySQL & MariaDB
+description: Tunnel MySQL connections through Pomerium
+---
+
+# Tunneled MySQL Connections
+
+This document explains how to connect to a MySQL or MariaDB database through an encrypted TCP tunnel. We use the `mysql` command line utility, but the same tunnel can be used by GUI tools.
+
+
+
+ ## Basic Connection
+
+ 1. Create a TCP tunnel, using either [`pomerium-cli`](/docs/releases.md#pomerium-cli) or the Pomerium Desktop client:
+
+ ::::: tabs
+ :::: tab pomerium-cli
+ ```bash
+ pomerium-cli tcp aService.corp.example.com:3306 --listen :3306
+ ```
+
+ :::tip --listen
+ The `--listen` flag is optional. It lets you define what port the tunnel listens on locally. If not specified, the client will choose a random available port.
+ :::
+
+ ::::
+ :::: tab Pomerium Desktop
+ 
+
+ :::tip Local Address
+ The **Local Address** field is optional. Using it defines what port the tunnel listens on locally. If not specified, Pomerium Desktop will choose a random available port.
+ :::
+
+ ::::
+ :::::
+
+1. Initiate your MySQL connection, pointing to `localhost`:
+
+ ```bash
+ mysql -h 127.0.0.1 -u USER -p
+ ```
+
+## Allow Access from Remote Hosts:
+
+1. Your MySQL or MariaDB service may not accept connections from remote hosts. Find the `bind-address` key in the configuration files (usually located in `/etc/mysql/`) and edit it to accept remote connections. For example:
+
+ ```ini
+ # Instead of skip-networking the default is now to listen only on
+ # localhost which is more compatible and is not less secure.
+ bind-address = 0.0.0.0
+ ```
+
+1. When connecting, you may get an error like `ERROR 1130 (HY000): Host '192.0.2.10' is not allowed to connect to this MariaDB/MySQL server`. You can create a user entry in your database for the Pomerium host:
+
+ ```sql
+ CREATE USER 'user'@'pomerium.local' IDENTIFIED BY 'some_pass';
+ GRANT ALL PRIVILEGES ON *.* TO 'user'@'pomerium.local'
+ ```
+
+ Or create a user entry with no host associated:
+
+ ```sql
+ CREATE USER 'user'@'%' IDENTIFIED BY 'some_pass';
+ GRANT ALL PRIVILEGES ON *.* TO 'user'@'%'
+ ```
+
+## More Resources
+
+- [Configuring MariaDB for Remote Client Access](https://mariadb.com/kb/en/configuring-mariadb-for-remote-client-access/)
+- [How to Allow Remote Connections to MySQL Database Server](https://linuxize.com/post/mysql-remote-access/)
\ No newline at end of file
diff --git a/docs/docs/tcp/rdp.md b/docs/docs/tcp/rdp.md
new file mode 100644
index 000000000..43f1fa400
--- /dev/null
+++ b/docs/docs/tcp/rdp.md
@@ -0,0 +1,70 @@
+---
+title: RDP
+description: Tunnel RDP connections through Pomerium
+---
+
+# Tunneled RDP Connections
+
+Remote Desktop Protocol (**RDP**) is a standard for using a desktop computer remotely. It was released by Microsoft and is most commonly used to access Windows systems, but can be used for macOS and Linux systems as well.
+
+## Basic Connection
+
+1. Create a TCP tunnel, using either [`pomerium-cli`](/docs/releases.md#pomerium-cli) or the Pomerium Desktop client:
+
+ ::::: tabs
+ :::: tab pomerium-cli
+ ```bash
+ pomerium-cli tcp aService.corp.example.com:3389 --listen :3389
+ ```
+
+ :::tip --listen
+ The `--listen` flag is optional. It lets you define what port the tunnel listens on locally. If not specified, the client will choose a random available port.
+ :::
+
+ ::::
+ :::: tab Pomerium Desktop
+ 
+
+ :::tip Local Address
+ The **Local Address** field is optional. Using it defines what port the tunnel listens on locally. If not specified, Pomerium Desktop will choose a random available port.
+ :::
+
+ ::::
+ :::::
+
+1. Initiate your RDP connection, pointing to `localhost`. This example uses the [Remmina](https://remmina.org/) client, but the procedure should be similar for other tools:
+
+ 
+
+ ::: warning
+ The first connection attempt will initiate a redirect to authenticate you in the browser. Once you're signed in, subsequent connections will succeed. If your client isn't configured to retry the connection, you may have to reconnect manually.
+ :::
+
+
+## Always Tunnel through Pomerium
+
+Some clients, like Remmina, support running commands before and after connection. The script below (adopted from [this example](https://kgibran.wordpress.com/2019/03/13/remmina-rdp-ssh-tunnel-with-pre-and-post-scripts/) using SSH tunnels) starts and stops an instance of `pomerium-cli`:
+
+<<< @/examples/tcp/pomerium-tunnel.sh
+
+1. Save the script above to your home folder (`~/`), and make it executable:
+
+ ```bash
+ cd ~/
+ wget https://github.com/pomerium/pomerium/blob/master/examples/tcp/pomerium-tunnel.sh
+ chmod +x pomerium-tunnel.sh
+ ```
+
+1. Update your client profile to execute the script before and after the connection:
+
+ 
+
+::: warning
+Flatpak versions of client software may not be able to read external scripts or programs.
+:::
+
+## More Resources
+
+- [Remote Desktop Protocol (Wikipedia)](https://en.wikipedia.org/wiki/Remote_Desktop_Protocol)
+- [Remmina (Linux)](https://remmina.org/)
+- [Microsoft Remote Desktop (macOS)](https://apps.apple.com/us/app/microsoft-remote-desktop/id1295203466?mt=12)
\ No newline at end of file
diff --git a/docs/docs/topics/tcp-support.md b/docs/docs/tcp/readme.md
similarity index 67%
rename from docs/docs/topics/tcp-support.md
rename to docs/docs/tcp/readme.md
index 94ea61a7e..7c27c2372 100644
--- a/docs/docs/topics/tcp-support.md
+++ b/docs/docs/tcp/readme.md
@@ -9,8 +9,6 @@ meta:
# TCP Support
-## About
-
Operations and engineering teams frequently require access to lower level administrative and data protocols such as SSH, RDP, Postgres, MySQL, Redis, etc.
In addition to managing HTTP based applications, Pomerium can be used to protect non-HTTP systems with the same consistent authorization policy. This is achieved by tunneling TCP over HTTP with the help of a client side command built into [`pomerium-cli`](/docs/releases.md#pomerium-cli).
@@ -24,7 +22,7 @@ To minimize issues with TCP support, Pomerium should not be placed behind anothe
Otherwise, the HTTP proxy in front of Pomerium must know how to properly handle the `CONNECT` command and proxy it upstream. This capability will be specific to each proxy implementation.
:::
-## Configuring
+## Configure Routes
TCP configuration is simple. Just specify the correct scheme and ports in your route [`to`](/reference/readme.md#to) and [`from`](/reference/readme.md#from) fields.
@@ -42,20 +40,21 @@ routes:
has: "datascience@example.com"
```
-Notes:
+When creating TCP routes, note the following:
-* When configuring a TCP route, any HTTP specific settings such as `regex_rewrite_pattern`, or `set_request_headers` have no effect.
-* While data is encrypted from a user system to Pomerium's proxy, the underlying application protocol must also support encryption for data to be fully encrypted end-to-end.
-* The ports in `from` and `to` are independent. Users only need to know the `from` URL to connect. The `to` can be changed without end user participation.
+- When configuring a TCP route, any HTTP specific settings such as `regex_rewrite_pattern` or `set_request_headers` have no effect.
+- While data is encrypted from a user system to Pomerium's proxy, the underlying application protocol must also support encryption for data to be fully encrypted end-to-end. Otherwise, traffic from the Pomerium proxy service to the upstream service will be unencrypted.
+- The ports in `from` and `to` are independent. Users only need to know the `from` URL to connect. The `to` can be changed without end user participation.
+- The port defined in `from` does not dictate what port the tunneled traffic uses. This will always be the port defined by [`address`](/reference/readme.md#address) in your Pomerium configuration (`443` by default). The port instead differentiates multiple routes to the same hostname for different services.
-## Using
+## Connect to TCP Routes
While HTTP routes can be consumed with just a normal browser, `pomerium-cli` must serve as a proxy for TCP routes. It is [available](/docs/releases.md#pomerium-cli) for a variety of platforms in various formats.
To connect, you normally need just the external hostname and port of your TCP route:
-```bash
-% pomerium-cli tcp redis.corp.example.com:6379
+```bash{1}
+pomerium-cli tcp redis.corp.example.com:6379
5:57PM INF tcptunnel: listening on 127.0.0.1:52046
```
@@ -63,7 +62,7 @@ By default, `pomerium-cli` will start a listener on loopback on a random port.
On first connection, you will be sent through a standard Pomerium HTTP authentication flow. After completing this, your TCP connection should be established!
-```bash
+```bash{1}
% redis-cli -h localhost -p 52046
localhost:52046> keys *
(empty array)
@@ -78,32 +77,21 @@ You may specify an optional address and port for the `tcp` command to listen on.
`-` specifies that STDIN and STDOUT should be directly attached to the remote TCP connection. This is useful for [SSH](#ssh-helper-configuration) or for sending data through a shell pipe.
-### SSH Helper Configuration
-
-A sample SSH ProxyCommand configuration in `ssh_config`:
-
-```
-Host *.corp.example.com
- ProxyCommand ~/bin/pomerium-cli tcp --listen - %h:%p
-```
-
-A sample SSH command using `pomerium-cli` as a ProxyCommand:
-
-```bash
-ssh -o ProxyCommand='pomerium-cli tcp --listen - %h:%p' ssh.localhost.pomerium.io
-```
-
-More information on SSH ProxyCommand:
-
-- [https://man.openbsd.org/ssh_config.5#ProxyCommand](https://man.openbsd.org/ssh_config.5#ProxyCommand)
-- [https://www.redhat.com/sysadmin/ssh-proxy-bastion-proxyjump](https://www.redhat.com/sysadmin/ssh-proxy-bastion-proxyjump)
-
### Custom URL
-If the Pomerium proxy is not reachable through port `443` or the route is not in external DNS, a custom URL may be specified:
+If the Pomerium proxy is not reachable through port `443` or the route is not in external DNS, you can specify a custom URL:
```bash
-% pomerium-cli tcp --pomerium-url https://pomerium.corp.example.com:8443 redis.corp.example.com:6379
+pomerium-cli tcp --pomerium-url https://pomerium.corp.example.com:8443 redis.corp.example.com:6379
```
-The above command connects to `https://pomerium.corp.example.com:8443` and then requests the TCP route named `redis.corp.example.com:6379`.
+The command above connects to `https://pomerium.corp.example.com:8443` and then requests the TCP route for `redis.corp.example.com:6379`.
+
+## Service-Specific Documentation
+
+We've outlined how to use a TCP tunnel through Pomerium for several popular services that use TCP connections:
+
+- [MySQL and MariaDB](./mysql.md)
+- [RDP](./rdp.md)
+- [Redis](./redis.md)
+- [SSH](./ssh.md)
diff --git a/docs/docs/tcp/redis.md b/docs/docs/tcp/redis.md
new file mode 100644
index 000000000..d99c68172
--- /dev/null
+++ b/docs/docs/tcp/redis.md
@@ -0,0 +1,46 @@
+---
+title: Redis
+description: Tunnel Redis connections through Pomerium
+---
+
+# Tunneled Redis Connections
+
+Redis is a popular in-memory data structure store. It can be run locally or configured as a single or distributed standalone service.
+
+## Basic Connection
+
+ 1. Create a TCP tunnel, using either [`pomerium-cli`](/docs/releases.md#pomerium-cli) or the Pomerium Desktop client:
+
+ ::::: tabs
+ :::: tab pomerium-cli
+ ```bash
+ pomerium-cli tcp redis.corp.example.com:6379 --listen :6379
+ ```
+
+ :::tip --listen
+ The `--listen` flag is optional. It lets you define what port the tunnel listens on locally. If not specified, the client will choose a random available port.
+ :::
+
+ ::::
+
+ :::: tab Pomerium Desktop
+ 
+ :::tip Local Address
+ The **Local Address** field is optional. Using it defines what port the tunnel listens on locally. If not specified, Pomerium Desktop will choose a random available port.
+ :::
+
+ ::::
+ :::::
+
+1. Initiate your Redis connection, pointing to `localhost`:
+
+ ```bash
+ redis-cli -h localhost -p 6379
+ ```
+
+This demonstrates access to a Redis server through Pomerium from the `redis-cli` tool. Pomerium Enterprise users can utilize [Service Accounts](/enterprise/service-accounts.md) to enable secure machine-to-machine communication of Redis services.
+
+## More Resources
+
+- [redis-cli](https://redis.io/topics/rediscli)
+- [Redis ACL](https://redis.io/topics/acl)
\ No newline at end of file
diff --git a/docs/docs/tcp/service-template.md b/docs/docs/tcp/service-template.md
new file mode 100644
index 000000000..22943dbb6
--- /dev/null
+++ b/docs/docs/tcp/service-template.md
@@ -0,0 +1,57 @@
+---
+title: $SERVICE
+description: Tunnel $SERVICE connections through Pomerium
+layout: Draft
+---
+
+# Tunneled $SERVICE Connections
+
+This is a template to standardize how we document connections to popular services through a Pomerium TCP tunnel. It's not listed in the site map, so if you're not a Pomerium employee and you're reading this, you're either looking at our open-source code base, or... ¯\_(ツ)_/¯
+
+Replace the paragraph above with a brief description of the service, and/or why you would want to tunnel traffic to it.
+
+
+
+ ## Basic Connection
+
+ 1. Create a TCP tunnel, using either [`pomerium-cli`](/docs/releases.md#pomerium-cli) or the Pomerium Desktop client:
+
+ ::::: tabs
+ :::: tab pomerium-cli
+ ```bash
+ pomerium-cli tcp aService.corp.example.com:$COMMON-PORT --listen :$ANOTHER-PORT
+ ```
+
+ :::tip --listen
+ The `--listen` flag is optional. It lets you define what port the tunnel listens on locally. If not specified, the client will choose a random available port.
+ :::
+
+ ::::
+ :::: tab Pomerium Desktop
+ \
+
+ :::tip Local Address
+ The **Local Address** field is optional. Using it defines what port the tunnel listens on locally. If not specified, Pomerium Desktop will choose a random available port.
+ :::
+
+ ::::
+ :::::
+
+1. Initiate your $SERVICE connection, pointing to `localhost`:
+
+ ```bash
+ $COMMAND
+ ```
+ Optionally, if the service is accessed through GUI software, include a screenshot here. If both are commonly used, show both using tabs.
+
+## Tunnel and Connect Simultaneously
+
+If $COMMAND has a method of initiating the `pomerium-cli` tunnel as it attempts to connect, document it here.
+
+## Always Tunnel through Pomerium
+
+If the client software can be configured to automatically initiate a `pomerium-cli` tunnel when connecting, document that here.
+
+## More Resources
+
+Always include at least one or two links in a bulleted list that could help the reader.
\ No newline at end of file
diff --git a/docs/docs/tcp/ssh.md b/docs/docs/tcp/ssh.md
new file mode 100644
index 000000000..f70b9ccb7
--- /dev/null
+++ b/docs/docs/tcp/ssh.md
@@ -0,0 +1,76 @@
+---
+title: SSH
+description: Tunnel SSH connections through Pomerium
+---
+
+# Tunneled SSH Connections
+
+Bad actors are constantly scanning the internet for exposed SSH services. Changing the default port obfuscates, but doesn't protect the service, and implementing and updating advanced SSH authentication can be cumbersome.
+
+By tunneling SSH connections through your Pomerium service:
+
+ - All traffic is encrypted twice (once by the Pomerium TCP connection, once by SSH itself),
+ - The SSH service can remain closed to the internet, or even restricted to only accept connections from the Pomerium proxy service
+ - Authentication and authorization is managed by Pomerium, using your IdP for identity, and can be easily managed at scale.
+
+ ## Basic Connection
+
+ 1. Create a TCP tunnel, using either [`pomerium-cli`](/docs/releases.md#pomerium-cli) or the Pomerium Desktop client:
+
+ ::::: tabs
+ :::: tab pomerium-cli
+ ```bash
+ pomerium-cli tcp aService.corp.example.com:22 --listen :2202
+ ```
+
+ :::tip --listen
+ The `--listen` flag is optional. It lets you define what port the tunnel listens on locally. If not specified, the client will choose a random available port.
+ :::
+
+ ::::
+ :::: tab Pomerium Desktop
+ 
+
+ :::tip Local Address
+ The **Local Address** field is optional. Using it defines what port the tunnel listens on locally. If not specified, Pomerium Desktop will choose a random available port.
+ :::
+
+ ::::
+ :::::
+
+1. Initiate your SSH connection, pointing to `localhost`:
+
+ ```bash
+ ssh user@localhost -p 2202
+ ```
+
+## Tunnel and Connect Simultaneously
+
+The process outlined above requires multiple steps and terminal environments (when using the CLI) or programs (when using the Desktop Client). By invoking `pomerium-cli` when the connection is made, you can streamline the process into a single connection:
+
+```bash
+ssh -o ProxyCommand='pomerium-cli tcp --listen - %h:%p' ssh.localhost.pomerium.io
+```
+
+## Always Tunnel through Pomerium
+
+Once your SSH service is configured and tested through Pomerium, you can edit your local SSH configuration file to always create a tunnel when connecting to that service:
+
+```bash
+Host aService.corp.example.com
+ ProxyCommand /usr/bin/pomerium-cli tcp --listen - %h:%p
+```
+
+You can even configure all SSH connections to your domain space to use the tunnel:
+
+```bash
+Host *.corp.example.com
+ ProxyCommand /usr/bin/pomerium-cli tcp --listen - %h:%p
+```
+
+## More Resources
+
+For more information on SSH ProxyCommand, see:
+
+- [ProxyCommand (SSH man page)](https://man.openbsd.org/ssh_config.5#ProxyCommand)
+- [SSH to remote hosts though a proxy or bastion with ProxyJump (RedHat blog)](https://www.redhat.com/sysadmin/ssh-proxy-bastion-proxyjump)
\ No newline at end of file
diff --git a/docs/docs/upgrading.md b/docs/docs/upgrading.md
index fcba43f5a..579e42e2b 100644
--- a/docs/docs/upgrading.md
+++ b/docs/docs/upgrading.md
@@ -109,7 +109,7 @@ The `administrators` configuration option has been removed.
### TCP Proxying
-Pomerium can now be used for non-HTTP services. See [documentation](/docs/topics/tcp-support.md) for more details.
+Pomerium can now be used for non-HTTP services. See [documentation](/docs/tcp/readme.md) for more details.
### Datadog Tracing
diff --git a/docs/enterprise/reference/manage.md b/docs/enterprise/reference/manage.md
index 036c90196..5045516a6 100644
--- a/docs/enterprise/reference/manage.md
+++ b/docs/enterprise/reference/manage.md
@@ -27,7 +27,7 @@ This value is only visible in the Console UI.
`From` is the externally accessible URL for the proxied request.
-Specifying `tcp+https` for the scheme enables [TCP proxying](/docs/topics/tcp-support.md) support for the route. You may map more than one port through the same hostname by specifying a different `:port` in the URL.
+Specifying `tcp+https` for the scheme enables [TCP proxying](/docs/tcp/readme.md) support for the route. You may map more than one port through the same hostname by specifying a different `:port` in the URL.
:::warning
diff --git a/docs/guides/tcp.md b/docs/guides/tcp.md
index 47b5e6a6b..613c8d2a8 100644
--- a/docs/guides/tcp.md
+++ b/docs/guides/tcp.md
@@ -10,7 +10,7 @@ description: >-
# Securing TCP based services
-The following guide demonstrates how to use Pomerium's [TCP Proxying](/docs/topics/tcp-support.md) support with various TCP services such as databases and other non-HTTP protocols. It also covers integration points with them when possible.
+The following guide demonstrates how to use Pomerium's [TCP Proxying](/docs/tcp/readme.md) support with various TCP services such as databases and other non-HTTP protocols. It also covers integration points with them when possible.
The source files from this guide can be found on [GitHub](https://github.com/pomerium/pomerium/tree/master/examples/tcp/).
diff --git a/docs/reference/readme.md b/docs/reference/readme.md
index 569d1a323..a5091c050 100644
--- a/docs/reference/readme.md
+++ b/docs/reference/readme.md
@@ -1174,7 +1174,7 @@ Requires setting [Google Cloud Serverless Authentication Service Account](#googl
`From` is the externally accessible URL for the proxied request.
-Specifying `tcp+https` for the scheme enables [TCP proxying](/docs/topics/tcp-support.md) support for the route. You may map more than one port through the same hostname by specifying a different `:port` in the URL.
+Specifying `tcp+https` for the scheme enables [TCP proxying](/docs/tcp/readme.md) support for the route. You may map more than one port through the same hostname by specifying a different `:port` in the URL.
:::warning
diff --git a/docs/reference/settings.yaml b/docs/reference/settings.yaml
index 628e0d9e3..4a5f9fa8e 100644
--- a/docs/reference/settings.yaml
+++ b/docs/reference/settings.yaml
@@ -1294,7 +1294,7 @@ settings:
doc: |
`From` is the externally accessible URL for the proxied request.
- Specifying `tcp+https` for the scheme enables [TCP proxying](/docs/topics/tcp-support.md) support for the route. You may map more than one port through the same hostname by specifying a different `:port` in the URL.
+ Specifying `tcp+https` for the scheme enables [TCP proxying](/docs/tcp/readme.md) support for the route. You may map more than one port through the same hostname by specifying a different `:port` in the URL.
:::warning
diff --git a/examples/tcp/pomerium-tunnel.sh b/examples/tcp/pomerium-tunnel.sh
new file mode 100644
index 000000000..c66f1417e
--- /dev/null
+++ b/examples/tcp/pomerium-tunnel.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+scriptname="$(basename $0)"
+
+if [ $# -lt 3 ]
+ then
+ echo "Usage: $scriptname start | stop POMERIUM_ROUTE LOCAL_PORT"
+ exit
+fi
+
+case "$1" in
+
+start)
+ echo "Starting Pomerium Tunnel to $2"
+ pomerium-cli tcp $2 --listen $3 &
+ ;;
+stop)
+ echo "Stopping Pomerium tunnel to $3"
+ kill $(pgrep -f "pomerium-cli tcp $2 --listen $3")
+ ;;
+*)
+ echo "Did not understand your argument, please use start|stop"
+ ;;
+
+esac