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 6 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
2 changes: 2 additions & 0 deletions app/Commands/Dns/SetHost.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ public function handle(): void
if ($this->option('restore')) {
$mechanic->restoreNetworking();
app(Config::class)->updateIp('127.0.0.1');
$this->porter->restart('dns');

return;
}

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

namespace App\Commands\Ngrok;

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

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;
}

app(Porter::class)->stop('ngrok');
Keoghan marked this conversation as resolved.
Show resolved Hide resolved

$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();
}

app(Porter::class)->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 (app(Mechanic::class)->isUsingDefaultHostAddress()) {
$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;
}
}
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
{
//
}
42 changes: 42 additions & 0 deletions app/Support/Mechanics/MacOs.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace App\Support\Mechanics;

use App\Support\Mechanics\Exceptions\UnableToRetrieveIP;

class MacOs extends Untrained
{
/** @var string $hostAddress Address for Host */
Expand Down Expand Up @@ -101,4 +103,44 @@ public function getHostAddress()
{
return $this->hostAddress;
}

/**
* Does a Porter domain resolve to the Host Address.
*
* @throws UnableToRetrieveIP
*
* @return bool
*/
public function isUsingHostAddress()
{
return $this->getPorterDomainIp() === $this->getHostAddress();
}

/**
* Does a Porter domain resolve to 127.0.0.1.
*
* @throws UnableToRetrieveIP
*
* @return bool
*/
public function isUsingDefaultHostAddress()
{
return $this->getPorterDomainIp() === '127.0.0.1';
Keoghan marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Determine the working IP for Porter.
*
* @throws UnableToRetrieveIP
*
* @return string
*/
public function getPorterDomainIp()
{
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'];
}
}
14 changes: 14 additions & 0 deletions app/Support/Mechanics/Mechanic.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,18 @@ public function restoreNetworking();
* Get Host IP address.
*/
public function getHostAddress();

/**
* Does a porter domain resolve to the Host Address.
Keoghan marked this conversation as resolved.
Show resolved Hide resolved
*
* @return bool
*/
public function isUsingHostAddress();

/**
* Does a porter domain resolve to 127.0.0.1.
*
* @return bool
*/
public function isUsingDefaultHostAddress();
}
20 changes: 20 additions & 0 deletions app/Support/Mechanics/Untrained.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,24 @@ public function getHostAddress()
{
return $this->hostAddress;
}

/**
* Does a porter domain resolve to the Host Address.
*
* @return bool
*/
public function isUsingHostAddress()
{
$this->iAmNotTrainedTo('determine if we are using the Host Address for Porter');
}

/**
* Does a porter domain resolve to 127.0.0.1.
*
* @return bool
*/
public function isUsingDefaultHostAddress()
{
$this->iAmNotTrainedTo('determine if we are using the Default Host Address for Porter');
}
}
5 changes: 3 additions & 2 deletions resources/image_sets/konsulting/porter-ubuntu/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"mysql": "mysql:5.7",
"redis": "redis:alpine",
"dns": "andyshinn\/dnsmasq",
"mailhog": "mailhog\/mailhog:v1.0.0"
"mailhog": "mailhog\/mailhog:v1.0.0",
"ngrok": "wernight/ngrok"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

@include("{$imageSet->getName()}::node")

@include("{$imageSet->getName()}::ngrok")

@foreach($activePhpVersions as $key => $version)
# PHP version {!! $version->version_number !!}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ngrok:
image: {{ $imageSet->firstByServiceName('ngrok')->getName() }}
ports:
- 4040:4040
networks:
- porter