Skip to content

Commit

Permalink
Adding ngrok to more easily share progress on dev sites (#68)
Browse files Browse the repository at this point in the history
* Add ngrok command
  - allow specification of region 
  - allow specification of site
  - allow disabling of inspection

* ngrok documentation

* Refactor Mechanic to make usage of alternative loopback address clearer
  • Loading branch information
Keoghan committed Oct 10, 2019
1 parent 3ee5ba8 commit 23bbf05
Show file tree
Hide file tree
Showing 26 changed files with 476 additions and 58 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,18 @@ Redis data is stored in `~/.porter/data/redis`.

We leave it up to you to run this command at the moment, it is a temporary setting and resets on a machine restart. Not everyone will need it, and we'd rather not dig much deeper into your system to make it permanent.

## Ngrok

- `porter ngrok {site?} {--region=eu} {--no-inspection}`

It's sometimes handy to share your progress on a site without deploying it to a server out there in the world. [ngrok](https://ngrok.com) provides a decent solution for this. Porter provides an ngrok container which is able to forward your local site to an external url.

You can optionally specify a site to ngrok (e.g. `konsulting.test` would be `konsulting`). You can also specify a region and optionally disable inspections of responses by ngrok.

The ngrok UI interface will be available here: [http://0.0.0.0:4040](http://0.0.0.0:4040)

In order to use ngrok, you need to use an alternative loopback address to 127.0.0.1, since this resolves to the container that a request is sent from otherwise. This can be done by following [these instructions](#dns).

## Email

We have a [MailHog](https://github.com/mailhog/MailHog) container; all emails are routed to this container from PHP when using the `mail()` function.
Expand Down
3 changes: 1 addition & 2 deletions app/Commands/Dns/Flush.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace App\Commands\Dns;

use App\Commands\BaseCommand;
use App\Support\Mechanics\Mechanic;

class Flush extends BaseCommand
{
Expand All @@ -28,6 +27,6 @@ class Flush extends BaseCommand
*/
public function handle(): void
{
app(Mechanic::class)->flushDns();
$this->porterLibrary->getMechanic()->flushDns();
}
}
13 changes: 6 additions & 7 deletions app/Commands/Dns/SetHost.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use App\Commands\BaseCommand;
use App\Support\Dnsmasq\Config;
use App\Support\Mechanics\Mechanic;

class SetHost extends BaseCommand
{
Expand All @@ -29,16 +28,16 @@ class SetHost extends BaseCommand
*/
public function handle(): void
{
$mechanic = app(Mechanic::class);

if ($this->option('restore')) {
$mechanic->restoreNetworking();
app(Config::class)->updateIp('127.0.0.1');
$this->porterLibrary->getMechanic()->removeAlternativeLoopbackAddress();
app(Config::class)->updateIp($this->porterLibrary->getMechanic()->getStandardLoopback());
$this->porter->restart('dns');

return;
}

$mechanic->setupNetworking();
app(Config::class)->updateIp($mechanic->getHostAddress());
$this->porterLibrary->getMechanic()->addAlternativeLoopbackAddress();
app(Config::class)->updateIp($this->porterLibrary->getMechanic()->getAlternativeLoopback());
$this->porter->restart('dns');
}
}
95 changes: 95 additions & 0 deletions app/Commands/Ngrok/Open.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace App\Commands\Ngrok;

use App\Commands\BaseCommand;
use App\Models\Site;
use App\Support\Mechanics\Exceptions\UnableToRetrieveIP;

class Open extends BaseCommand
{
/**
* The signature of the command.
*
* @var string
*/
protected $signature = 'ngrok {site?} {--region=eu} {--no-inspection}';

/**
* The description of the command.
*
* @var string
*/
protected $description = 'Open ngrok connection to forward your dev environment to an external url';

/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$site = Site::resolveFromPathOrCurrentWorkingDirectory($this->argument('site'));
$wasSecure = false;

if (!$site) {
$this->error('No site at this location, and no site path provided.');

return;
}

if (!$this->checkItWillResolveProperly()) {
return;
}

if ($site->secure) {
$this->info('Removing SSL for site (required for free ngrok version)');
$site->unsecure();
$wasSecure = true;
}

$this->porter->stop('ngrok');

$tls = ' -bind-tls='.($wasSecure ? 'true' : 'false');
$region = ' -region='.$this->option('region');
$inspect = ' -inspect='.($this->option('no-inspection') ? 'false' : 'true');

$this->dockerCompose
->runContainer('ngrok')
->append("ngrok http -host-header=rewrite{$region}{$tls}{$inspect} {$site->url}:80")
->interactive()
->perform();

if ($wasSecure) {
$this->info('Restoring SSL for site');
$site->secure();
}

$this->porter->stop('ngrok');
}

/**
* Checking that Porter is using the dns:set-host IP. If we don't ngrok
* requests will only resolve to 127.0.0.1 which is internal to the
* ngrok container, and results in a useless 502 error.
*
* @return bool
*/
public function checkItWillResolveProperly()
{
try {
if ($this->porterLibrary->getMechanic()->isUsingStandardLoopback()) {
$this->info('You need to use an alternative loopback address.');
$this->info('Please run porter dns:set-host and review the documentation here: https://github.com/konsulting/porter#dns');

return false;
}
} catch (UnableToRetrieveIP $e) {
$this->info('Please run porter dns:flush and try again. You may need to give it a little while.');

return false;
}

return true;
}
}
1 change: 1 addition & 0 deletions app/Models/Site.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
class Site extends Model
{
protected $guarded = [];
protected $casts = ['secure' => 'boolean'];

/**
* PHP Version.
Expand Down
24 changes: 24 additions & 0 deletions app/PorterLibrary.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ public function __construct(FilePublisher $filePublisher, Mechanic $mechanic, $p
$this->mechanic = $mechanic;
}

/**
* Set the Mechanic instance.
*
* @param Mechanic $mechanic
*
* @return $this
*/
public function setMechanic(Mechanic $mechanic)
{
$this->mechanic = $mechanic;

return $this;
}

/**
* Return the path for storing container config files.
*
Expand Down Expand Up @@ -272,4 +286,14 @@ protected function createDirectoryStructure()
}
}
}

/**
* Return the Mechanic instance.
*
* @return Mechanic
*/
public function getMechanic()
{
return $this->mechanic;
}
}
15 changes: 15 additions & 0 deletions app/Support/Console/DockerCompose/NullCliCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace App\Support\Console\DockerCompose;

class NullCliCommand extends CliCommand
{
/**
* Execute the command.
*
* @return string|null
*/
public function perform()
{
}
}
8 changes: 8 additions & 0 deletions app/Support/Mechanics/Exceptions/UnableToRetrieveIP.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace App\Support\Mechanics\Exceptions;

class UnableToRetrieveIP extends \Exception
{
//
}
34 changes: 21 additions & 13 deletions app/Support/Mechanics/MacOs.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

namespace App\Support\Mechanics;

use App\Support\Mechanics\Exceptions\UnableToRetrieveIP;

class MacOs extends Untrained
{
/** @var string $hostAddress Address for Host */
protected $hostAddress = '10.200.10.1';
/** @var string Alternative Loopback Address */
protected $alternativeLoopback = '10.200.10.1';

/**
* Trust the given root certificate file in the Keychain.
Expand Down Expand Up @@ -61,44 +63,50 @@ public function flushDns()
}

/**
* Set up networking for Mac.
* Add the alternative loopback address to the system.
*
* Add a loopback alias to 10.200.10.1. This is then used as the IP for DNS resolution, otherwise
* we get weird results when trying to access services hosted in docker (since they resolve
* 127.0.0.1 to the requesting container).
*
* @return void
*/
public function setupNetworking()
public function addAlternativeLoopbackAddress()
{
$this->consoleWriter->info("Adding loopback alias to {$this->hostAddress}/24. Please provide your sudo password.");
$this->consoleWriter->info("Adding loopback alias to {$this->alternativeLoopback}/24. Please provide your sudo password.");

$command = "sudo ifconfig lo0 alias {$this->hostAddress}/24";
$command = "sudo ifconfig lo0 alias {$this->alternativeLoopback}/24";

$this->cli->passthru($command);
}

/**
* Restore networking on Mac.
* Remove the alternative loopback address from the system.
*
* @return void
*/
public function restoreNetworking()
public function removeAlternativeLoopbackAddress()
{
$this->consoleWriter->info("Removing loopback alias to {$this->hostAddress}. Please provide your sudo password.");
$this->consoleWriter->info("Removing loopback alias to {$this->alternativeLoopback}. Please provide your sudo password.");

$command = "sudo ifconfig lo0 -alias {$this->hostAddress}";
$command = "sudo ifconfig lo0 -alias {$this->alternativeLoopback}";

$this->cli->passthru($command);
}

/**
* Return the host IP address in use.
* Determine the working IP for Porter.
*
* @throws UnableToRetrieveIP
*
* @return string
*/
public function getHostAddress()
public function getPorterDomainIp()
{
return $this->hostAddress;
if (($records = dns_get_record('www.unlikely-domain-name.'.setting('domain'))) === []) {
throw new UnableToRetrieveIP();
}

return $records[0]['ip'];
}
}
42 changes: 36 additions & 6 deletions app/Support/Mechanics/Mechanic.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,51 @@ public function getUserHomePath();
public function flushDns();

/**
* Setup networking for Porter.
* Add the alternative loopback address to the system.
*
* @return void
*/
public function setupNetworking();
public function addAlternativeLoopbackAddress();

/**
* Restore networking.
* Remove the alternative loopback address from the system.
*
* @return void
*/
public function restoreNetworking();
public function removeAlternativeLoopbackAddress();

/**
* Get Host IP address.
* Get standard loopback address.
*
* @return string
*/
public function getStandardLoopback();

/**
* Get alternative loopback address.
*
* @return string
*/
public function getAlternativeLoopback();

/**
* Does a Porter domain resolve to the standard loopback address.
*
* @return bool
*/
public function isUsingAlternativeLoopback();

/**
* Does a Porter domain resolve to the standard loopback address?
*
* @return bool
*/
public function isUsingStandardLoopback();

/**
* Determine the working IP for Porter.
*
* @return string
*/
public function getHostAddress();
public function getPorterDomainIp();
}

0 comments on commit 23bbf05

Please sign in to comment.