Skip to content

Add documentation and example for MySQL database SSH tunnel #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ matrix:
include:
- php: 5.3
dist: precise
install: composer remove react/mysql --dev --no-interaction # do not install react/mysql example on legacy PHP
allow_failures:
- php: hhvm

Expand Down
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ existing higher-level protocol implementation.
* [Plain TCP connections](#plain-tcp-connections)
* [Secure TLS connections](#secure-tls-connections)
* [HTTP requests](#http-requests)
* [Database tunnel](#database-tunnel)
* [Connection timeout](#connection-timeout)
* [DNS resolution](#dns-resolution)
* [Password authentication](#password-authentication)
Expand Down Expand Up @@ -323,6 +324,51 @@ When using the `SshSocksConnector` (recommended), this works for both plain HTTP
and TLS-encrypted HTTPS requests. When using the `SshProcessConnector`, this only
works for plaintext HTTP requests.

### Database tunnel

We should now have a basic understanding of how we can tunnel any TCP/IP-based
protocol over an SSH proxy server. Besides using this to access "external"
services, this is also particularly useful because it allows you to access
network services otherwise only local to this SSH server from the outside, such
as a firewalled database server.

For example, this allows us to combine an
[async MySQL database client](https://github.com/friends-of-reactphp/mysql) and
the above SSH proxy server setup, so we can access a firewalled MySQL database
server through an SSH tunnel. Here's the gist:

```php
$loop = React\EventLoop\Factory::create();
$proxy = new Clue\React\SshProxy\SshProcessConnector('user@example.com', $loop);

$uri = 'test:test@localhost/test';
$factory = new React\MySQL\Factory($loop, $proxy);
$connection = $factory->createLazyConnection($uri);

$connection->query('SELECT * FROM book')->then(
function (QueryResult $command) {
echo count($command->resultRows) . ' row(s) in set' . PHP_EOL;
},
function (Exception $error) {
echo 'Error: ' . $error->getMessage() . PHP_EOL;
}
);

$connection->quit();

$loop->run();
```

See also [example #21](examples) for more details.

This example will automatically launch the `ssh` client binary to create the
connection to a database server that can not otherwise be accessed from the
outside. From the perspective of the database server, this looks just like a
regular, local connection. From this code's perspective, this will create a
regular, local connection which just happens to use a secure SSH tunnel to
transport this to a remote server, so you can send any query like you would to a
local database server.

### Connection timeout

By default, neither the `SshProcessConnector` nor the `SshSocksConnector` implement
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
},
"require-dev": {
"clue/block-react": "^1.3",
"phpunit/phpunit": "^7.4 || ^6.4 || ^5.0 || ^4.8.36"
"phpunit/phpunit": "^7.4 || ^6.4 || ^5.0 || ^4.8.36",
"react/mysql": "^0.5.3"
}
}
37 changes: 37 additions & 0 deletions examples/21-mysql-ssh-tunnel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

// A more advanced example to show how a MySQL server can be accessed through an SSH tunnel.
// The SSH proxy can be given through the SSH_PROXY env and defaults to localhost otherwise.
// The MySQL server can be given through the MYSQL_LOGIN env and default to localhost otherwise.
//
// You can assign the SSH_PROXY and MYSQL_LOGIN environment and prefix this with
// a space to make sure your login credentials are not stored in your bash
// history like this:
//
// $ export SSH_PROXY=user:secret@example.com
// $ export MYSQL_LOGIN=user:password@localhost
// $ php examples/21-mysql-ssh-tunnel.php
//
// See also https://github.com/friends-of-reactphp/mysql

use Clue\React\SshProxy\SshProcessConnector;
use React\MySQL\Factory;
use React\MySQL\QueryResult;

require __DIR__ . '/../vendor/autoload.php';

$loop = React\EventLoop\Factory::create();

$url = getenv('SSH_PROXY') !== false ? getenv('SSH_PROXY') : 'ssh://localhost:22';
$proxy = new SshProcessConnector($url, $loop);

$url = getenv('MYSQL_LOGIN') !== false ? getenv('MYSQL_LOGIN') : 'user:pass@localhost';
$factory = new Factory($loop, $proxy);
$client = $factory->createLazyConnection($url);

$client->query('SELECT * FROM (SELECT "foo" UNION SELECT "bar") data')->then(function (QueryResult $query) {
var_dump($query->resultRows);
}, 'printf');
$client->quit();

$loop->run();