1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-02-04 16:44:04 +00:00

Remove unfinished features, expand README

This commit is contained in:
Samuel Štancl 2019-02-07 15:22:57 +01:00
parent 97ab962cb7
commit 256e88444c
6 changed files with 29 additions and 214 deletions

View file

@ -396,15 +396,38 @@ Tenant migrations are located in `database/migrations/tenant`, so you should mov
## HTTPS certificates ## HTTPS certificates
todo HTTPS certificates are very easy to deal with if you use the `yourclient1.yourapp.com`, `yourclient2.yourapp.com` model. You can use a wildcard HTTPS certificate.
```sh If you use the model where second level domains are used, there are multiple ways you can solve this.
sudo mkdir /var/lib/letsencrypt_tenancy /var/log/letsencrypt_tenancy /etc/letsencrypt_tenancy
# replace ubuntu with your username This guide focuses on nginx.
sudo chown -R ubuntu:www-data /var/lib/letsencrypt_tenancy /var/log/letsencrypt_tenancy /etc/letsencrypt_tenancy
sudo chmod -R 775 /var/lib/letsencrypt_tenancy /var/log/letsencrypt_tenancy /etc/letsencrypt_tenancy ### 1. Use nginx with the lua module
Specifically, you're interested in the [`ssl_certificate_by_lua_block`](https://github.com/openresty/lua-nginx-module#ssl_certificate_by_lua_block) directive. Nginx doesn't support using variables such as the hostname in the `ssl_certificate` directive, which is why the lua module is needed.
This approach lets you use one server block for all tenants.
### 2. Add a simple server block for each tenant
You can store most of your config in a file, such as `/etc/nginx/includes/tenant`, and include this file into tenant server blocks.
```nginx
server {
include includes/tenant;
server_name foo.bar;
# ssl_certificate /etc/foo/...;
}
``` ```
### Generating certificates
You can generate a certificate using certbot. If you use the `--nginx` flag, you will need to run certbot as root. If you use the `--webroot` flag, you only need the user that runs it to have write access to the webroot directory (or perhaps webroot/.well-known is enough) and some certbot files (you can specify these using --work-dir, --config-dir and --logs-dir).
Creating this config dynamically from PHP is not easy, but is probably feasible. Giving `www-data` write access to `/etc/nginx/sites-available/tenants.conf` should work.
However, you still need to reload nginx configuration to apply the changes to configuration. This is problematic and I'm not sure if there is a simple and secure way to do this from PHP.
## Testing ## Testing
If you run the tests of this package, please make sure you don't store anything in Redis @ 127.0.0.1:6379 db#14. The contents of this database are flushed everytime the tests are run. If you run the tests of this package, please make sure you don't store anything in Redis @ 127.0.0.1:6379 db#14. The contents of this database are flushed everytime the tests are run.

View file

@ -1,9 +0,0 @@
<?php
namespace Stancl\Tenancy\Interfaces;
interface ServerConfigManager
{
public function addVhost(string $domain, string $file): bool;
public function deployCertificate(string $domain): bool;
}

View file

@ -1,39 +0,0 @@
<?php
namespace Stancl\Tenancy\ServerConfigManagers;
use Symfony\Component\Process\Process;
use Stancl\Tenancy\Interfaces\ServerConfigManager;
class NginxConfigManager implements ServerConfigManager
{
public function addVhost(string $domain, string $file): bool
{
$f = fopen($file, 'a');
$fw = fwrite($f, $this->getVhostText($domain));
$fc = fclose($f);
return $fw && $fc;
}
public function getVhostText(string $domain)
{
return str_replace('%host%', $domain, config('tenancy.server.nginx.vhost'));
}
public function deployCertificate(string $domain): bool
{
$process = new Process(array_merge([
config('tenancy.server.certbot_path'),
'-n',
'--webroot',
'-d', $domain,
'--agree-tos',
'--preferred-challenges', 'http',
'--webroot-path', config('tenancy.server.nginx.webroot'),
], config('tenancy.server.nginx.extra_certbot_args')));
$process->run();
return $process->isSuccessful();
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace Stancl\Tenancy;
use Stancl\Tenancy\Interfaces\ServerConfigManager;
class ServerManager
{
public function __construct(ServerConfigManager $serverConfigManager, TenantManager $tenantManager)
{
$this->serverConfigManager = $serverConfigManager;
$this->tenantManager = $tenantManager;
}
public function getConfigFilePath()
{
if (config('tenancy.server.file.single')) {
return config('tenancy.server.file.path');
}
return config('tenancy.server.file.path.prefix') . $this->tenantManager->tenant['uuid'] . config('tenancy.server.file.path.suffix');
}
public function createVhost(string $domain)
{
// todo symlink
$this->serverConfigManager->addVhost($domain, $this->getConfigFilePath());
$this->serverConfigManager->deployCertificate($domain);
if (method_exists($this->serverConfigManager, 'postCertDeploymentChanges')) {
$this->serverConfigManager->postCertDeploymentChanges();
}
}
public function deleteVhost()
{
// todo
}
}

View file

@ -30,35 +30,4 @@ return [
// 's3', // 's3',
], ],
], ],
'server' => [
'manager' => 'Stancl\Tenancy\ServerConfigManagers\NginxConfigManager',
'file' => [
'single' => true, // single file for all tenant vhosts
'path' => '/etc/nginx/sites-available/tenants.conf',
/*
'single' => false,
'path' => [
'prefix' => '/etc/nginx/sites-available/tenants/tenant',
'suffix' => '.conf',
// results in: '/etc/nginx/sites-available/tenants/tenant' . $uuid . '.conf'
]
*/
],
'nginx' => [
'webroot' => '/var/www/html',
'vhost' => "
server {
include includes/tenancy;
server_name %host%;
}",
'extra_certbot_args' => [
'--must-staple',
'--config-dir', '/etc/letsencrypt_tenancy',
'--work-dir', '/var/lib/letsencrypt_tenancy',
'--logs-dir', '/var/log/letsencrypt_tenancy',
'--staging', // obtains a fake cert intended for testing certbot
// '--email', 'your@email', // if you haven't created an account in certbot yet
],
],
]
]; ];

View file

@ -1,91 +0,0 @@
<?php
namespace Stancl\Tenancy\Tests;
use Stancl\Tenancy\ServerManager;
class ServerManagerTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->serverManager = app(ServerManager::class);
}
/** @test */
public function getConfigFilePath_works_when_single_file_mode_is_used()
{
config([
'tenancy.server.file.single' => true,
'tenancy.server.file.path' => '/foo/bar',
]);
$this->assertSame('/foo/bar', $this->serverManager->getConfigFilePath());
}
/** @test */
public function getConfigFilePath_works_when_multiple_files_mode_is_used()
{
config([
'tenancy.server.file.single' => false,
'tenancy.server.file.path' => [
'prefix' => '/etc/foo',
'suffix' => 'bar'
],
]);
$uuid = tenant('uuid');
$this->assertSame("/etc/foo{$uuid}bar", $this->serverManager->getConfigFilePath());
}
/** @test */
public function vhost_is_written()
{
[$tmpfile, $path, $vhost] = $this->setupCreateVhost();
$this->serverManager->createVhost('localhost');
$vhost = str_replace('%host%', 'localhost', $vhost);
$this->assertContains($vhost, fread($tmpfile, filesize($path)));
}
/** @test */
public function cert_is_deployed()
{
[$tmpfile, $path, $vhost] = $this->setupCreateVhost();
$this->serverManager->createVhost('localhost');
dump(fread($tmpfile, filesize($path)));
// todo
}
public function setupCreateVhost()
{
$tmpfile = tmpfile();
$path = stream_get_meta_data($tmpfile)['uri'];
$vhost = "server {
include includes/tenancy;
server_name %host%;
}";
config([
'tenancy.server.nginx' => [
'vhost' => $vhost,
'extra_certbot_args' => [
'--staging'
],
],
'tenancy.server.file' => [
'single' => true,
'path' => $path,
],
]);
return [$tmpfile, $path, $vhost];
}
}