Skip to content
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

Adding ngrok to more easily share progress on dev sites #68

Merged
merged 16 commits into from
Oct 10, 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
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'))) === []) {
Keoghan marked this conversation as resolved.
Show resolved Hide resolved
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();
}
Loading