mirror of
https://github.com/laravel/valet.git
synced 2026-02-06 00:40:06 +01:00
Add proxy site-handling commands
valet proxy domain host valet unproxy domain valet proxies (to list all recognized proxy site configs)
This commit is contained in:
@@ -145,6 +145,75 @@ function parked()
|
|||||||
return $parkedLinks;
|
return $parkedLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all sites which are proxies (not Links, and contain proxy_pass directive)
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
function proxies()
|
||||||
|
{
|
||||||
|
$dir = VALET_HOME_PATH.'/Nginx/';
|
||||||
|
$tld = $this->config->read()['tld'];
|
||||||
|
$links = $this->links();
|
||||||
|
$certsPath = VALET_HOME_PATH.'/Certificates';
|
||||||
|
$certs = $this->getCertificates($certsPath);
|
||||||
|
|
||||||
|
$proxies = collect($this->files->scandir($dir))
|
||||||
|
->filter(function ($site, $key) use ($tld) {
|
||||||
|
// keep sites that match our TLD
|
||||||
|
return ends_with($site, '.'.$tld);
|
||||||
|
})->map(function ($site, $key) use ($tld) {
|
||||||
|
// remove the TLD suffix for consistency
|
||||||
|
return str_replace('.'.$tld, '', $site);
|
||||||
|
})->reject(function ($site, $key) use ($links) {
|
||||||
|
return $links->has($site);
|
||||||
|
})->mapWithKeys(function ($site) {
|
||||||
|
$host = $this->getProxyHostForSite($site) ?: '(other)';
|
||||||
|
return [$site => $host];
|
||||||
|
})->reject(function ($host, $site) {
|
||||||
|
// If proxy host is null, it may be just a normal SSL stub, or something else; either way we exclude it from the list
|
||||||
|
return $host === '(other)';
|
||||||
|
})->map(function ($host, $site) use ($certs) {
|
||||||
|
$secured = $certs->has($site);
|
||||||
|
$url = ($secured ? 'https': 'http').'://'.$site;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'site' => $site,
|
||||||
|
'secured' => $secured ? ' X': '',
|
||||||
|
'url' => $url,
|
||||||
|
'path' => $host,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return $proxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify whether a site is for a proxy by reading the host name from its config file.
|
||||||
|
*
|
||||||
|
* @param string $site Site name without TLD
|
||||||
|
* @param string $configContents Config file contents
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getProxyHostForSite($site, $configContents = null)
|
||||||
|
{
|
||||||
|
$siteConf = $configContents ?: $this->getSiteConfigFileContents($site);
|
||||||
|
$host = null;
|
||||||
|
if (preg_match('~proxy_pass\s+(?<host>https?://.*)\s*;~', $siteConf, $patterns)) {
|
||||||
|
$host = trim($patterns['host']);
|
||||||
|
}
|
||||||
|
return $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSiteConfigFileContents($site, $dir = null)
|
||||||
|
{
|
||||||
|
$config = $this->config->read();
|
||||||
|
$dir = $dir ?: VALET_HOME_PATH.'/Nginx/';
|
||||||
|
$suffix = '.'.$config['tld'];
|
||||||
|
$file = $dir.str_replace($suffix,'',$site).$suffix;
|
||||||
|
return $this->files->get($file);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all certificates from config folder.
|
* Get all certificates from config folder.
|
||||||
*
|
*
|
||||||
@@ -265,14 +334,43 @@ function resecureForNewTld($oldTld, $tld)
|
|||||||
$secured = $this->secured();
|
$secured = $this->secured();
|
||||||
|
|
||||||
foreach ($secured as $url) {
|
foreach ($secured as $url) {
|
||||||
$this->unsecure($url);
|
$newUrl = str_replace('.'.$oldTld, '.'.$tld, $url);
|
||||||
}
|
$siteConf = $this->getSiteConfigFileContents($url);
|
||||||
|
|
||||||
foreach ($secured as $url) {
|
if (strpos($siteConf, '# valet stub: proxy.valet.conf') === 0) {
|
||||||
$this->secure(str_replace('.'.$oldTld, '.'.$tld, $url));
|
$this->unsecure($url);
|
||||||
|
$this->secure($newUrl, $this->replaceOldDomainWithNew($siteConf, '.'.$url, '.'.$newUrl));
|
||||||
|
} else {
|
||||||
|
$this->unsecure($url);
|
||||||
|
$this->secure($newUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse Nginx site config file contents to swap old domain to new.
|
||||||
|
*
|
||||||
|
* @param string $siteConf Nginx site config content
|
||||||
|
* @param string $old Old domain
|
||||||
|
* @param string $new New domain
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function replaceOldDomainWithNew($siteConf, $old, $new)
|
||||||
|
{
|
||||||
|
$lookups = [];
|
||||||
|
$lookups[] = '~server_name .*;~';
|
||||||
|
$lookups[] = '~error_log .*;~';
|
||||||
|
|
||||||
|
foreach ($lookups as $lookup) {
|
||||||
|
preg_match($lookup, $siteConf, $matches);
|
||||||
|
foreach ($matches as $match) {
|
||||||
|
$replaced = str_replace($old, $new, $match);
|
||||||
|
$siteConf = str_replace($match, $replaced, $siteConf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $siteConf;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all of the URLs that are currently secured.
|
* Get all of the URLs that are currently secured.
|
||||||
*
|
*
|
||||||
@@ -290,9 +388,10 @@ function secured()
|
|||||||
* Secure the given host with TLS.
|
* Secure the given host with TLS.
|
||||||
*
|
*
|
||||||
* @param string $url
|
* @param string $url
|
||||||
|
* @param string $siteConf pregenerated Nginx config file contents
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function secure($url)
|
function secure($url, $siteConf = null)
|
||||||
{
|
{
|
||||||
$this->unsecure($url);
|
$this->unsecure($url);
|
||||||
|
|
||||||
@@ -305,7 +404,7 @@ function secure($url)
|
|||||||
$this->createCertificate($url);
|
$this->createCertificate($url);
|
||||||
|
|
||||||
$this->files->putAsUser(
|
$this->files->putAsUser(
|
||||||
VALET_HOME_PATH.'/Nginx/'.$url, $this->buildSecureNginxServer($url)
|
VALET_HOME_PATH.'/Nginx/'.$url, $this->buildSecureNginxServer($url, $siteConf)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,16 +552,21 @@ function buildCertificateConf($path, $url)
|
|||||||
* Build the TLS secured Nginx server for the given URL.
|
* Build the TLS secured Nginx server for the given URL.
|
||||||
*
|
*
|
||||||
* @param string $url
|
* @param string $url
|
||||||
|
* @param string $siteConf (optional) Nginx site config file content
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function buildSecureNginxServer($url)
|
function buildSecureNginxServer($url, $siteConf = null)
|
||||||
{
|
{
|
||||||
$path = $this->certificatesPath();
|
$path = $this->certificatesPath();
|
||||||
|
|
||||||
|
if ($siteConf === null) {
|
||||||
|
$siteConf = $this->files->get(__DIR__.'/../stubs/secure.valet.conf');
|
||||||
|
}
|
||||||
|
|
||||||
return str_replace(
|
return str_replace(
|
||||||
['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX', 'VALET_SITE', 'VALET_CERT', 'VALET_KEY'],
|
['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX', 'VALET_SITE', 'VALET_CERT', 'VALET_KEY'],
|
||||||
[VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $url, $path.'/'.$url.'.crt', $path.'/'.$url.'.key'],
|
[VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $url, $path.'/'.$url.'.crt', $path.'/'.$url.'.key'],
|
||||||
$this->files->get(__DIR__.'/../stubs/secure.valet.conf')
|
$siteConf
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,6 +626,56 @@ function unsecureAll()
|
|||||||
info('unsecure --all was successful.');
|
info('unsecure --all was successful.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the Nginx proxy config for the specified domain
|
||||||
|
*
|
||||||
|
* @param string $url The domain name to serve
|
||||||
|
* @param string $host The URL to proxy to, eg: http://127.0.0.1:8080
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function proxyCreate($url, $host)
|
||||||
|
{
|
||||||
|
if (!preg_match('~^https?://.*$~', $host)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('"%s" is not a valid URL', $host));
|
||||||
|
}
|
||||||
|
|
||||||
|
$tld = $this->config->read()['tld'];
|
||||||
|
if (!ends_with($url, '.'.$tld)) {
|
||||||
|
$url .= '.'.$tld;
|
||||||
|
}
|
||||||
|
|
||||||
|
$siteConf = $this->files->get(__DIR__.'/../stubs/proxy.valet.conf');
|
||||||
|
|
||||||
|
$siteConf = str_replace(
|
||||||
|
['VALET_HOME_PATH', 'VALET_SERVER_PATH', 'VALET_STATIC_PREFIX', 'VALET_SITE', 'VALET_PROXY_HOST'],
|
||||||
|
[VALET_HOME_PATH, VALET_SERVER_PATH, VALET_STATIC_PREFIX, $url, $host],
|
||||||
|
$siteConf
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->secure($url, $siteConf);
|
||||||
|
|
||||||
|
info('Valet will now proxy [https://'.$url.'] traffic to ['.$host.'].');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsecure the given URL so that it will use HTTP again.
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function proxyDelete($url)
|
||||||
|
{
|
||||||
|
$tld = $this->config->read()['tld'];
|
||||||
|
if (!ends_with($url, '.'.$tld)) {
|
||||||
|
$url .= '.'.$tld;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->unsecure($url);
|
||||||
|
$this->files->unlink(VALET_HOME_PATH.'/Nginx/'.$url);
|
||||||
|
|
||||||
|
info('Valet will no longer proxy [https://'.$url.'].');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the path to the linked Valet sites.
|
* Get the path to the linked Valet sites.
|
||||||
*
|
*
|
||||||
|
|||||||
95
cli/stubs/proxy.valet.conf
Normal file
95
cli/stubs/proxy.valet.conf
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# valet stub: proxy.valet.conf
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 127.0.0.1:80;
|
||||||
|
server_name VALET_SITE www.VALET_SITE *.VALET_SITE;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 127.0.0.1:443 ssl http2;
|
||||||
|
server_name VALET_SITE www.VALET_SITE *.VALET_SITE;
|
||||||
|
root /;
|
||||||
|
charset utf-8;
|
||||||
|
client_max_body_size 128M;
|
||||||
|
http2_push_preload on;
|
||||||
|
|
||||||
|
location /VALET_STATIC_PREFIX/ {
|
||||||
|
internal;
|
||||||
|
alias /;
|
||||||
|
try_files $uri $uri/;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_certificate "VALET_CERT";
|
||||||
|
ssl_certificate_key "VALET_KEY";
|
||||||
|
|
||||||
|
location = /favicon.ico { access_log off; log_not_found off; }
|
||||||
|
location = /robots.txt { access_log off; log_not_found off; }
|
||||||
|
|
||||||
|
access_log off;
|
||||||
|
error_log "VALET_HOME_PATH/Log/VALET_SITE-error.log";
|
||||||
|
|
||||||
|
error_page 404 "VALET_SERVER_PATH";
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass VALET_PROXY_HOST;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Client-Verify SUCCESS;
|
||||||
|
proxy_set_header X-Client-DN $ssl_client_s_dn;
|
||||||
|
proxy_set_header X-SSL-Subject $ssl_client_s_dn;
|
||||||
|
proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_read_timeout 1800;
|
||||||
|
proxy_connect_timeout 1800;
|
||||||
|
chunked_transfer_encoding on;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_buffering off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\.ht {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 127.0.0.1:60;
|
||||||
|
server_name VALET_SITE www.VALET_SITE *.VALET_SITE;
|
||||||
|
root /;
|
||||||
|
charset utf-8;
|
||||||
|
client_max_body_size 128M;
|
||||||
|
|
||||||
|
add_header X-Robots-Tag 'noindex, nofollow, nosnippet, noarchive';
|
||||||
|
|
||||||
|
location /VALET_STATIC_PREFIX/ {
|
||||||
|
internal;
|
||||||
|
alias /;
|
||||||
|
try_files $uri $uri/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /favicon.ico { access_log off; log_not_found off; }
|
||||||
|
location = /robots.txt { access_log off; log_not_found off; }
|
||||||
|
|
||||||
|
access_log off;
|
||||||
|
error_log "VALET_HOME_PATH/Log/VALET_SITE-error.log";
|
||||||
|
|
||||||
|
error_page 404 "VALET_SERVER_PATH";
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass VALET_PROXY_HOST;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\.ht {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -181,6 +181,35 @@
|
|||||||
info('The ['.$url.'] site will now serve traffic over HTTP.');
|
info('The ['.$url.'] site will now serve traffic over HTTP.');
|
||||||
})->descriptions('Stop serving the given domain over HTTPS and remove the trusted TLS certificate');
|
})->descriptions('Stop serving the given domain over HTTPS and remove the trusted TLS certificate');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an Nginx proxy config for the specified domain
|
||||||
|
*/
|
||||||
|
$app->command('proxy domain host', function ($domain, $host) {
|
||||||
|
|
||||||
|
Site::proxyCreate($domain, $host);
|
||||||
|
Nginx::restart();
|
||||||
|
|
||||||
|
})->descriptions('Create an Nginx proxy site for the specified host. Useful for docker, mailhog etc.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an Nginx proxy config
|
||||||
|
*/
|
||||||
|
$app->command('unproxy domain', function ($domain) {
|
||||||
|
|
||||||
|
Site::proxyDelete($domain);
|
||||||
|
Nginx::restart();
|
||||||
|
|
||||||
|
})->descriptions('Delete an Nginx proxy config.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display all of the sites that are proxies.
|
||||||
|
*/
|
||||||
|
$app->command('proxies', function () {
|
||||||
|
$proxies = Site::proxies();
|
||||||
|
|
||||||
|
table(['Site', 'SSL', 'URL', 'Host'], $proxies->all());
|
||||||
|
})->descriptions('Display all of the proxy sites');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine which Valet driver the current directory is using.
|
* Determine which Valet driver the current directory is using.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user