mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-03 12:34:08 +00:00
Compare commits
48 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce165719d6 | ||
|
|
4f543ce20f | ||
|
|
55f957df21 | ||
|
|
38f59b9410 | ||
|
|
ebe6655349 | ||
|
|
038ea08ca7 | ||
|
|
ba424efd39 | ||
|
|
75aef0e60b | ||
|
|
eda8b34297 | ||
|
|
d8151ddb2e | ||
|
|
928345c8ea | ||
|
|
52d6fb51d5 | ||
|
|
06d7c69487 | ||
|
|
756c7f81ca | ||
|
|
d7af57a95e | ||
|
|
f9c469497e | ||
|
|
7ecbedb48a | ||
|
|
76878f66b9 | ||
|
|
b9afef50c4 | ||
|
|
83ebd1e649 | ||
|
|
76431c3fd5 | ||
|
|
96a4d0bbb0 | ||
|
|
4cfc739730 | ||
|
|
a95bd906bc | ||
|
|
21795cf788 | ||
|
|
6e98fd9403 | ||
|
|
ead1edc2b9 | ||
|
|
db822cb876 | ||
|
|
65bfce43c0 | ||
|
|
50fc05ab52 | ||
|
|
c9cf5c486f | ||
|
|
379f4b9dff | ||
|
|
aa02b8d433 | ||
|
|
70ecb92e82 | ||
|
|
d5cc2a2eed | ||
|
|
2b91bd24c5 | ||
|
|
5e8ac1b48e | ||
|
|
dc86170ef5 | ||
|
|
0232cf5b4c | ||
|
|
6e73f7f2e4 | ||
|
|
6c5a1c317a | ||
|
|
b09a9f871e | ||
|
|
b5506f006b | ||
|
|
a6c3594448 | ||
|
|
5dd3952230 | ||
|
|
22ec0f8826 | ||
|
|
da6e04bb1a | ||
|
|
1bfce6716c |
@@ -52,7 +52,7 @@ class StartMongodb
|
|||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => [
|
'test' => [
|
||||||
'CMD-SHELL',
|
'CMD-SHELL',
|
||||||
'mongo --eval "printjson(db.serverStatus())" | grep uptime | grep -v grep'
|
'mongosh --eval "printjson(db.runCommand(\"ping\"))"'
|
||||||
],
|
],
|
||||||
'interval' => '5s',
|
'interval' => '5s',
|
||||||
'timeout' => '5s',
|
'timeout' => '5s',
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ use App\Models\Application;
|
|||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use App\Models\StandaloneMongodb;
|
use App\Models\StandaloneMongodb;
|
||||||
|
use App\Models\StandaloneMysql;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use App\Models\StandaloneRedis;
|
use App\Models\StandaloneRedis;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class Init extends Command
|
class Init extends Command
|
||||||
{
|
{
|
||||||
@@ -21,8 +23,24 @@ class Init extends Command
|
|||||||
ray()->clearAll();
|
ray()->clearAll();
|
||||||
$this->cleanup_in_progress_application_deployments();
|
$this->cleanup_in_progress_application_deployments();
|
||||||
$this->cleanup_stucked_resources();
|
$this->cleanup_stucked_resources();
|
||||||
|
// $this->cleanup_ssh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function cleanup_ssh()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$files = Storage::allFiles('ssh/keys');
|
||||||
|
foreach ($files as $file) {
|
||||||
|
Storage::delete($file);
|
||||||
|
}
|
||||||
|
$files = Storage::allFiles('ssh/mux');
|
||||||
|
foreach ($files as $file) {
|
||||||
|
Storage::delete($file);
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
echo "Error: {$e->getMessage()}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
private function cleanup_in_progress_application_deployments()
|
private function cleanup_in_progress_application_deployments()
|
||||||
{
|
{
|
||||||
// Cleanup any failed deployments
|
// Cleanup any failed deployments
|
||||||
@@ -37,11 +55,12 @@ class Init extends Command
|
|||||||
echo "Error: {$e->getMessage()}\n";
|
echo "Error: {$e->getMessage()}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private function cleanup_stucked_resources() {
|
private function cleanup_stucked_resources()
|
||||||
|
{
|
||||||
// Cleanup any resources that are not attached to any environment or destination or server
|
// Cleanup any resources that are not attached to any environment or destination or server
|
||||||
try {
|
try {
|
||||||
$applications = Application::all();
|
$applications = Application::all();
|
||||||
foreach($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
if (!$application->environment) {
|
if (!$application->environment) {
|
||||||
ray('Application without environment', $application->name);
|
ray('Application without environment', $application->name);
|
||||||
$application->delete();
|
$application->delete();
|
||||||
@@ -52,7 +71,7 @@ class Init extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$postgresqls = StandalonePostgresql::all();
|
$postgresqls = StandalonePostgresql::all();
|
||||||
foreach($postgresqls as $postgresql) {
|
foreach ($postgresqls as $postgresql) {
|
||||||
if (!$postgresql->environment) {
|
if (!$postgresql->environment) {
|
||||||
ray('Postgresql without environment', $postgresql->name);
|
ray('Postgresql without environment', $postgresql->name);
|
||||||
$postgresql->delete();
|
$postgresql->delete();
|
||||||
@@ -63,7 +82,7 @@ class Init extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$redis = StandaloneRedis::all();
|
$redis = StandaloneRedis::all();
|
||||||
foreach($redis as $redis) {
|
foreach ($redis as $redis) {
|
||||||
if (!$redis->environment) {
|
if (!$redis->environment) {
|
||||||
ray('Redis without environment', $redis->name);
|
ray('Redis without environment', $redis->name);
|
||||||
$redis->delete();
|
$redis->delete();
|
||||||
@@ -74,7 +93,7 @@ class Init extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$mongodbs = StandaloneMongodb::all();
|
$mongodbs = StandaloneMongodb::all();
|
||||||
foreach($mongodbs as $mongodb) {
|
foreach ($mongodbs as $mongodb) {
|
||||||
if (!$mongodb->environment) {
|
if (!$mongodb->environment) {
|
||||||
ray('Mongodb without environment', $mongodb->name);
|
ray('Mongodb without environment', $mongodb->name);
|
||||||
$mongodb->delete();
|
$mongodb->delete();
|
||||||
@@ -84,8 +103,30 @@ class Init extends Command
|
|||||||
$mongodb->delete();
|
$mongodb->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$mysqls = StandaloneMysql::all();
|
||||||
|
foreach ($mysqls as $mysql) {
|
||||||
|
if (!$mysql->environment) {
|
||||||
|
ray('Mysql without environment', $mysql->name);
|
||||||
|
$mysql->delete();
|
||||||
|
}
|
||||||
|
if (!$mysql->destination()) {
|
||||||
|
ray('Mysql without destination', $mysql->name);
|
||||||
|
$mysql->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$mariadbs = StandaloneMysql::all();
|
||||||
|
foreach ($mariadbs as $mariadb) {
|
||||||
|
if (!$mariadb->environment) {
|
||||||
|
ray('Mariadb without environment', $mariadb->name);
|
||||||
|
$mariadb->delete();
|
||||||
|
}
|
||||||
|
if (!$mariadb->destination()) {
|
||||||
|
ray('Mariadb without destination', $mariadb->name);
|
||||||
|
$mariadb->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
$services = Service::all();
|
$services = Service::all();
|
||||||
foreach($services as $service) {
|
foreach ($services as $service) {
|
||||||
if (!$service->environment) {
|
if (!$service->environment) {
|
||||||
ray('Service without environment', $service->name);
|
ray('Service without environment', $service->name);
|
||||||
$service->delete();
|
$service->delete();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Jobs\DatabaseBackupJob;
|
|||||||
use App\Jobs\DockerCleanupJob;
|
use App\Jobs\DockerCleanupJob;
|
||||||
use App\Jobs\InstanceAutoUpdateJob;
|
use App\Jobs\InstanceAutoUpdateJob;
|
||||||
use App\Jobs\ContainerStatusJob;
|
use App\Jobs\ContainerStatusJob;
|
||||||
|
use App\Jobs\PullHelperImageJob;
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\ScheduledDatabaseBackup;
|
use App\Models\ScheduledDatabaseBackup;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
@@ -19,20 +20,35 @@ class Kernel extends ConsoleKernel
|
|||||||
protected function schedule(Schedule $schedule): void
|
protected function schedule(Schedule $schedule): void
|
||||||
{
|
{
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
|
// Instance Jobs
|
||||||
$schedule->command('horizon:snapshot')->everyMinute();
|
$schedule->command('horizon:snapshot')->everyMinute();
|
||||||
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
||||||
|
|
||||||
|
// Server Jobs
|
||||||
$this->check_scheduled_backups($schedule);
|
$this->check_scheduled_backups($schedule);
|
||||||
$this->check_resources($schedule);
|
$this->check_resources($schedule);
|
||||||
$this->cleanup_servers($schedule);
|
$this->cleanup_servers($schedule);
|
||||||
$this->check_scheduled_backups($schedule);
|
$this->check_scheduled_backups($schedule);
|
||||||
|
$this->pull_helper_image($schedule);
|
||||||
} else {
|
} else {
|
||||||
|
// Instance Jobs
|
||||||
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||||
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
||||||
$schedule->job(new CheckResaleLicenseJob)->hourly()->onOneServer();
|
$schedule->job(new CheckResaleLicenseJob)->hourly()->onOneServer();
|
||||||
|
|
||||||
|
// Server Jobs
|
||||||
$this->instance_auto_update($schedule);
|
$this->instance_auto_update($schedule);
|
||||||
$this->check_scheduled_backups($schedule);
|
$this->check_scheduled_backups($schedule);
|
||||||
$this->check_resources($schedule);
|
$this->check_resources($schedule);
|
||||||
$this->cleanup_servers($schedule);
|
$this->cleanup_servers($schedule);
|
||||||
|
$this->pull_helper_image($schedule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private function pull_helper_image($schedule)
|
||||||
|
{
|
||||||
|
$servers = Server::all()->where('settings.is_usable', true)->where('settings.is_reachable', true);
|
||||||
|
foreach ($servers as $server) {
|
||||||
|
$schedule->job(new PullHelperImageJob($server))->everyTenMinutes()->onOneServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private function cleanup_servers($schedule)
|
private function cleanup_servers($schedule)
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ class Controller extends BaseController
|
|||||||
} else {
|
} else {
|
||||||
$team = $user->teams()->first();
|
$team = $user->teams()->first();
|
||||||
}
|
}
|
||||||
|
if (is_null(data_get($user, 'email_verified_at'))){
|
||||||
|
$user->email_verified_at = now();
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
Auth::login($user);
|
Auth::login($user);
|
||||||
session(['currentTeam' => $team]);
|
session(['currentTeam' => $team]);
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Project\Database;
|
namespace App\Http\Livewire\Project\Database;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class BackupExecutions extends Component
|
class BackupExecutions extends Component
|
||||||
@@ -23,6 +24,29 @@ class BackupExecutions extends Component
|
|||||||
$this->emit('success', 'Backup deleted successfully.');
|
$this->emit('success', 'Backup deleted successfully.');
|
||||||
$this->emit('refreshBackupExecutions');
|
$this->emit('refreshBackupExecutions');
|
||||||
}
|
}
|
||||||
|
public function download($exeuctionId)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$execution = $this->backup->executions()->where('id', $exeuctionId)->first();
|
||||||
|
if (is_null($execution)) {
|
||||||
|
$this->emit('error', 'Backup execution not found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$filename = data_get($execution, 'filename');
|
||||||
|
$server = $execution->scheduledDatabaseBackup->database->destination->server;
|
||||||
|
$privateKeyLocation = savePrivateKeyToFs($server);
|
||||||
|
$disk = Storage::build([
|
||||||
|
'driver' => 'sftp',
|
||||||
|
'host' => $server->ip,
|
||||||
|
'port' => $server->port,
|
||||||
|
'username' => $server->user,
|
||||||
|
'privateKey' => $privateKeyLocation,
|
||||||
|
]);
|
||||||
|
return $disk->download($filename);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
public function refreshBackupExecutions(): void
|
public function refreshBackupExecutions(): void
|
||||||
{
|
{
|
||||||
$this->executions = $this->backup->executions;
|
$this->executions = $this->backup->executions;
|
||||||
|
|||||||
@@ -31,11 +31,17 @@ class All extends Component
|
|||||||
public function getDevView()
|
public function getDevView()
|
||||||
{
|
{
|
||||||
$this->variables = $this->resource->environment_variables->map(function ($item) {
|
$this->variables = $this->resource->environment_variables->map(function ($item) {
|
||||||
|
if ($item->is_shown_once) {
|
||||||
|
return "$item->key=(locked secret)";
|
||||||
|
}
|
||||||
return "$item->key=$item->value";
|
return "$item->key=$item->value";
|
||||||
})->sort()->join('
|
})->sort()->join('
|
||||||
');
|
');
|
||||||
if ($this->showPreview) {
|
if ($this->showPreview) {
|
||||||
$this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) {
|
$this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) {
|
||||||
|
if ($item->is_shown_once) {
|
||||||
|
return "$item->key=(locked secret)";
|
||||||
|
}
|
||||||
return "$item->key=$item->value";
|
return "$item->key=$item->value";
|
||||||
})->sort()->join('
|
})->sort()->join('
|
||||||
');
|
');
|
||||||
@@ -49,19 +55,27 @@ class All extends Component
|
|||||||
{
|
{
|
||||||
if ($isPreview) {
|
if ($isPreview) {
|
||||||
$variables = parseEnvFormatToArray($this->variablesPreview);
|
$variables = parseEnvFormatToArray($this->variablesPreview);
|
||||||
$existingVariables = $this->resource->environment_variables_preview();
|
|
||||||
$this->resource->environment_variables_preview()->delete();
|
|
||||||
} else {
|
} else {
|
||||||
$variables = parseEnvFormatToArray($this->variables);
|
$variables = parseEnvFormatToArray($this->variables);
|
||||||
$existingVariables = $this->resource->environment_variables();
|
|
||||||
$this->resource->environment_variables()->delete();
|
|
||||||
}
|
}
|
||||||
foreach ($variables as $key => $variable) {
|
foreach ($variables as $key => $variable) {
|
||||||
$found = $existingVariables->where('key', $key)->first();
|
$found = $this->resource->environment_variables()->where('key', $key)->first();
|
||||||
|
$foundPreview = $this->resource->environment_variables_preview()->where('key', $key)->first();
|
||||||
if ($found) {
|
if ($found) {
|
||||||
|
if ($found->is_shown_once) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$found->value = $variable;
|
$found->value = $variable;
|
||||||
$found->save();
|
$found->save();
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
if ($foundPreview) {
|
||||||
|
if ($foundPreview->is_shown_once) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$foundPreview->value = $variable;
|
||||||
|
$foundPreview->save();
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
$environment = new EnvironmentVariable();
|
$environment = new EnvironmentVariable();
|
||||||
$environment->key = $key;
|
$environment->key = $key;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ namespace App\Http\Livewire\Project\Shared\EnvironmentVariable;
|
|||||||
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class Show extends Component
|
class Show extends Component
|
||||||
{
|
{
|
||||||
@@ -13,29 +12,45 @@ class Show extends Component
|
|||||||
public ModelsEnvironmentVariable $env;
|
public ModelsEnvironmentVariable $env;
|
||||||
public ?string $modalId = null;
|
public ?string $modalId = null;
|
||||||
public bool $isDisabled = false;
|
public bool $isDisabled = false;
|
||||||
|
public bool $isLocked = false;
|
||||||
public string $type;
|
public string $type;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'env.key' => 'required|string',
|
'env.key' => 'required|string',
|
||||||
'env.value' => 'nullable',
|
'env.value' => 'nullable',
|
||||||
'env.is_build_time' => 'required|boolean',
|
'env.is_build_time' => 'required|boolean',
|
||||||
|
'env.is_shown_once' => 'required|boolean',
|
||||||
];
|
];
|
||||||
protected $validationAttributes = [
|
protected $validationAttributes = [
|
||||||
'key' => 'key',
|
'key' => 'Key',
|
||||||
'value' => 'value',
|
'value' => 'Value',
|
||||||
'is_build_time' => 'build',
|
'is_build_time' => 'Build Time',
|
||||||
|
'is_shown_once' => 'Shown Once',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->isDisabled = false;
|
|
||||||
if (Str::of($this->env->key)->startsWith('SERVICE_FQDN') || Str::of($this->env->key)->startsWith('SERVICE_URL')) {
|
|
||||||
$this->isDisabled = true;
|
|
||||||
}
|
|
||||||
$this->modalId = new Cuid2(7);
|
$this->modalId = new Cuid2(7);
|
||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
|
$this->checkEnvs();
|
||||||
|
}
|
||||||
|
public function checkEnvs()
|
||||||
|
{
|
||||||
|
$this->isDisabled = false;
|
||||||
|
if (str($this->env->key)->startsWith('SERVICE_FQDN') || str($this->env->key)->startsWith('SERVICE_URL')) {
|
||||||
|
$this->isDisabled = true;
|
||||||
|
}
|
||||||
|
if ($this->env->is_shown_once) {
|
||||||
|
$this->isLocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function lock()
|
||||||
|
{
|
||||||
|
$this->env->is_shown_once = true;
|
||||||
|
$this->env->save();
|
||||||
|
$this->checkEnvs();
|
||||||
|
$this->emit('refreshEnvs');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
$this->submit();
|
$this->submit();
|
||||||
|
|||||||
19
app/Http/Livewire/Project/Shared/Webhooks.php
Normal file
19
app/Http/Livewire/Project/Shared/Webhooks.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Webhooks extends Component
|
||||||
|
{
|
||||||
|
public $resource;
|
||||||
|
public ?string $deploywebhook = null;
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->deploywebhook = generateDeployWebhook($this->resource);
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.shared.webhooks');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ class DecideWhatToDoWithUser
|
|||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
if (!auth()->user() || !isCloud() || isInstanceAdmin()) {
|
if (!auth()->user() || !isCloud() || isInstanceAdmin()) {
|
||||||
if (!isCloud() && showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
|
if (!isCloud() && showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
|
||||||
return redirect('boarding');
|
return redirect('boarding');
|
||||||
}
|
}
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
private int $customPort = 22;
|
private int $customPort = 22;
|
||||||
|
|
||||||
|
private ?string $fullRepoUrl = null;
|
||||||
|
private ?string $branch = null;
|
||||||
|
|
||||||
public $tries = 1;
|
public $tries = 1;
|
||||||
public function __construct(int $application_deployment_queue_id)
|
public function __construct(int $application_deployment_queue_id)
|
||||||
{
|
{
|
||||||
@@ -350,7 +353,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->clone_repository();
|
$this->check_git_if_build_needed();
|
||||||
$this->set_base_dir();
|
$this->set_base_dir();
|
||||||
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
|
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
|
||||||
if (strlen($tag) > 128) {
|
if (strlen($tag) > 128) {
|
||||||
@@ -379,6 +382,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->clone_repository();
|
||||||
$this->cleanup_git();
|
$this->cleanup_git();
|
||||||
$this->generate_nixpacks_confs();
|
$this->generate_nixpacks_confs();
|
||||||
$this->generate_compose_file();
|
$this->generate_compose_file();
|
||||||
@@ -480,17 +484,16 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
private function prepare_builder_image()
|
private function prepare_builder_image()
|
||||||
{
|
{
|
||||||
$pull = "--pull=always";
|
|
||||||
$helperImage = config('coolify.helper_image');
|
$helperImage = config('coolify.helper_image');
|
||||||
if ($this->dockerConfigFileExists === 'OK') {
|
if ($this->dockerConfigFileExists === 'OK') {
|
||||||
$runCommand = "docker run {$pull} -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
$runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
||||||
} else {
|
} else {
|
||||||
$runCommand = "docker run {$pull} -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
$runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
"echo -n 'Pulling helper image from $helperImage.'",
|
"echo -n 'Preparing container with helper image: $helperImage.'",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
$runCommand,
|
$runCommand,
|
||||||
@@ -510,27 +513,44 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
private function check_git_if_build_needed()
|
||||||
|
{
|
||||||
|
$this->generate_git_import_commands();
|
||||||
|
$private_key = base64_encode($this->application->private_key->private_key);
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[
|
||||||
|
executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh")
|
||||||
|
],
|
||||||
|
[
|
||||||
|
executeInDocker($this->deployment_uuid, "echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa")
|
||||||
|
],
|
||||||
|
[
|
||||||
|
executeInDocker($this->deployment_uuid, "chmod 600 /root/.ssh/id_rsa")
|
||||||
|
],
|
||||||
|
[
|
||||||
|
executeInDocker($this->deployment_uuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git ls-remote {$this->fullRepoUrl} {$this->branch}"),
|
||||||
|
"hidden" => true,
|
||||||
|
"save" => "git_commit_sha"
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$this->commit = $this->saved_outputs->get('git_commit_sha')->before("\t");
|
||||||
|
}
|
||||||
private function clone_repository()
|
private function clone_repository()
|
||||||
{
|
{
|
||||||
|
$importCommands = $this->generate_git_import_commands();
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
"echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} (commit sha {$this->application->git_commit_sha}) to {$this->basedir}. '"
|
"echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} (commit sha {$this->application->git_commit_sha}) to {$this->basedir}. '"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
$this->importing_git_repository(), "hidden" => true
|
$importCommands, "hidden" => true
|
||||||
],
|
]
|
||||||
[
|
|
||||||
executeInDocker($this->deployment_uuid, "cd {$this->basedir} && git rev-parse HEAD"),
|
|
||||||
"hidden" => true,
|
|
||||||
"save" => "git_commit_sha"
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
$this->commit = $this->saved_outputs->get('git_commit_sha');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function importing_git_repository()
|
private function generate_git_import_commands()
|
||||||
{
|
{
|
||||||
|
$this->branch = $this->application->git_branch;
|
||||||
$commands = collect([]);
|
$commands = collect([]);
|
||||||
$git_clone_command = "git clone -q -b {$this->application->git_branch}";
|
$git_clone_command = "git clone -q -b {$this->application->git_branch}";
|
||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
@@ -545,6 +565,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
if ($this->source->getMorphClass() == 'App\Models\GithubApp') {
|
if ($this->source->getMorphClass() == 'App\Models\GithubApp') {
|
||||||
if ($this->source->is_public) {
|
if ($this->source->is_public) {
|
||||||
|
$this->fullRepoUrl = "{$this->source->html_url}/{$this->application->git_repository}";
|
||||||
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->basedir}";
|
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->basedir}";
|
||||||
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
||||||
|
|
||||||
@@ -552,14 +573,17 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
} else {
|
} else {
|
||||||
$github_access_token = generate_github_installation_token($this->source);
|
$github_access_token = generate_github_installation_token($this->source);
|
||||||
$commands->push(executeInDocker($this->deployment_uuid, "git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->basedir}"));
|
$commands->push(executeInDocker($this->deployment_uuid, "git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->basedir}"));
|
||||||
|
$this->fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git";
|
||||||
}
|
}
|
||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
|
$this->branch = "pull/{$this->pull_request_id}/head:$pr_branch_name";
|
||||||
$commands->push(executeInDocker($this->deployment_uuid, "cd {$this->basedir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
|
$commands->push(executeInDocker($this->deployment_uuid, "cd {$this->basedir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
|
||||||
}
|
}
|
||||||
return $commands->implode(' && ');
|
return $commands->implode(' && ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->application->deploymentType() === 'deploy_key') {
|
if ($this->application->deploymentType() === 'deploy_key') {
|
||||||
|
$this->fullRepoUrl = $this->application->git_repository;
|
||||||
$private_key = base64_encode($this->application->private_key->private_key);
|
$private_key = base64_encode($this->application->private_key->private_key);
|
||||||
$git_clone_command = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_repository} {$this->basedir}";
|
$git_clone_command = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_repository} {$this->basedir}";
|
||||||
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
||||||
@@ -572,10 +596,10 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
return $commands->implode(' && ');
|
return $commands->implode(' && ');
|
||||||
}
|
}
|
||||||
if ($this->application->deploymentType() === 'other') {
|
if ($this->application->deploymentType() === 'other') {
|
||||||
|
$this->fullRepoUrl = $this->application->git_repository;
|
||||||
$git_clone_command = "{$git_clone_command} {$this->application->git_repository} {$this->basedir}";
|
$git_clone_command = "{$git_clone_command} {$this->application->git_repository} {$this->basedir}";
|
||||||
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
||||||
$commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
|
$commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
|
||||||
ray($commands);
|
|
||||||
return $commands->implode(' && ');
|
return $commands->implode(' && ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -661,10 +685,12 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
|
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
|
||||||
$environment_variables = $this->generate_environment_variables($ports);
|
$environment_variables = $this->generate_environment_variables($ports);
|
||||||
|
|
||||||
$labels = generateLabelsApplication($this->application, $this->preview);
|
|
||||||
if (data_get($this->application, 'custom_labels')) {
|
if (data_get($this->application, 'custom_labels')) {
|
||||||
$labels = str($this->application->custom_labels)->explode(',')->toArray();
|
$labels = collect(str($this->application->custom_labels)->explode(',')->toArray());
|
||||||
|
} else {
|
||||||
|
$labels = collect(generateLabelsApplication($this->application, $this->preview));
|
||||||
}
|
}
|
||||||
|
$labels = $labels->merge(defaultLabels($this->application->id, $this->application->uuid, $this->pull_request_id))->toArray();
|
||||||
$docker_compose = [
|
$docker_compose = [
|
||||||
'version' => '3.8',
|
'version' => '3.8',
|
||||||
'services' => [
|
'services' => [
|
||||||
@@ -885,14 +911,14 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
|
|
||||||
private function generate_build_env_variables()
|
private function generate_build_env_variables()
|
||||||
{
|
{
|
||||||
$this->build_args = collect(["--build-arg SOURCE_COMMIT={$this->commit}"]);
|
$this->build_args = collect(["--build-arg SOURCE_COMMIT=\"{$this->commit}\""]);
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
foreach ($this->application->build_environment_variables as $env) {
|
foreach ($this->application->build_environment_variables as $env) {
|
||||||
$this->build_args->push("--build-arg {$env->key}={$env->value}");
|
$this->build_args->push("--build-arg {$env->key}=\"{$env->value}\"");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
foreach ($this->application->build_environment_variables_preview as $env) {
|
foreach ($this->application->build_environment_variables_preview as $env) {
|
||||||
$this->build_args->push("--build-arg {$env->key}={$env->value}");
|
$this->build_args->push("--build-arg {$env->key}=\"{$env->value}\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
ray("checking server status for {$this->server->id}");
|
// ray("checking server status for {$this->server->id}");
|
||||||
try {
|
try {
|
||||||
// ray()->clearAll();
|
// ray()->clearAll();
|
||||||
$serverUptimeCheckNumber = $this->server->unreachable_count;
|
$serverUptimeCheckNumber = $this->server->unreachable_count;
|
||||||
|
|||||||
45
app/Jobs/PullHelperImageJob.php
Normal file
45
app/Jobs/PullHelperImageJob.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class PullHelperImageJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $timeout = 1000;
|
||||||
|
|
||||||
|
public function middleware(): array
|
||||||
|
{
|
||||||
|
return [(new WithoutOverlapping($this->server->uuid))->dontRelease()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uniqueId(): string
|
||||||
|
{
|
||||||
|
return $this->server->uuid;
|
||||||
|
}
|
||||||
|
public function __construct(public Server $server)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$helperImage = config('coolify.helper_image');
|
||||||
|
ray("Pulling {$helperImage}");
|
||||||
|
instant_remote_process(["docker pull -q {$helperImage}"], $this->server, false);
|
||||||
|
ray('PullHelperImageJob done');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
send_internal_notification('PullHelperImageJob failed with: ' . $e->getMessage());
|
||||||
|
ray($e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ class EnvironmentVariable extends Model
|
|||||||
{
|
{
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
"key" => 'string',
|
'key' => 'string',
|
||||||
'value' => 'encrypted',
|
'value' => 'encrypted',
|
||||||
'is_build_time' => 'boolean',
|
'is_build_time' => 'boolean',
|
||||||
];
|
];
|
||||||
@@ -21,6 +21,10 @@ class EnvironmentVariable extends Model
|
|||||||
static::created(function ($environment_variable) {
|
static::created(function ($environment_variable) {
|
||||||
if ($environment_variable->application_id && !$environment_variable->is_preview) {
|
if ($environment_variable->application_id && !$environment_variable->is_preview) {
|
||||||
$found = ModelsEnvironmentVariable::where('key', $environment_variable->key)->where('application_id', $environment_variable->application_id)->where('is_preview', true)->first();
|
$found = ModelsEnvironmentVariable::where('key', $environment_variable->key)->where('application_id', $environment_variable->application_id)->where('is_preview', true)->first();
|
||||||
|
$application = Application::find($environment_variable->application_id);
|
||||||
|
if ($application->build_pack === 'dockerfile') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!$found) {
|
if (!$found) {
|
||||||
ModelsEnvironmentVariable::create([
|
ModelsEnvironmentVariable::create([
|
||||||
'key' => $environment_variable->key,
|
'key' => $environment_variable->key,
|
||||||
@@ -33,7 +37,8 @@ class EnvironmentVariable extends Model
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public function service() {
|
public function service()
|
||||||
|
{
|
||||||
return $this->belongsTo(Service::class);
|
return $this->belongsTo(Service::class);
|
||||||
}
|
}
|
||||||
protected function value(): Attribute
|
protected function value(): Attribute
|
||||||
@@ -55,9 +60,9 @@ class EnvironmentVariable extends Model
|
|||||||
$variable = Str::after($environment_variable, 'global.');
|
$variable = Str::after($environment_variable, 'global.');
|
||||||
$variable = Str::before($variable, '}}');
|
$variable = Str::before($variable, '}}');
|
||||||
$variable = Str::of($variable)->trim()->value;
|
$variable = Str::of($variable)->trim()->value;
|
||||||
// $environment_variable = GlobalEnvironmentVariable::where('name', $environment_variable)->where('team_id', $team_id)->first()?->value;
|
// $environment_variable = GlobalEnvironmentVariable::where('name', $environment_variable)->where('team_id', $team_id)->first()?->value;
|
||||||
ray('global env variable');
|
ray('global env variable');
|
||||||
return $environment_variable;
|
return $environment_variable;
|
||||||
}
|
}
|
||||||
return $environment_variable;
|
return $environment_variable;
|
||||||
}
|
}
|
||||||
@@ -77,5 +82,4 @@ class EnvironmentVariable extends Model
|
|||||||
set: fn (string $value) => Str::of($value)->trim(),
|
set: fn (string $value) => Str::of($value)->trim(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
|
|
||||||
class ServerSetting extends Model
|
class ServerSetting extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = [
|
protected $guarded = [];
|
||||||
'server_id',
|
|
||||||
'is_usable',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function server()
|
public function server()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,6 +42,20 @@ class StandaloneMongodb extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function mongoInitdbRootPassword(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function ($value) {
|
||||||
|
try {
|
||||||
|
return decrypt($value);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
$this->mongo_initdb_root_password = encrypt($value);
|
||||||
|
$this->save();
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
public function portsMappings(): Attribute
|
public function portsMappings(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
@@ -63,7 +77,8 @@ class StandaloneMongodb extends BaseModel
|
|||||||
{
|
{
|
||||||
return 'standalone-mongodb';
|
return 'standalone-mongodb';
|
||||||
}
|
}
|
||||||
public function getDbUrl(bool $useInternal = false) {
|
public function getDbUrl(bool $useInternal = false)
|
||||||
|
{
|
||||||
if ($this->is_public && !$useInternal) {
|
if ($this->is_public && !$useInternal) {
|
||||||
return "mongodb://{$this->mongo_initdb_root_username}:{$this->mongo_initdb_root_password}@{$this->destination->server->getIp}:{$this->public_port}/?directConnection=true";
|
return "mongodb://{$this->mongo_initdb_root_username}:{$this->mongo_initdb_root_password}@{$this->destination->server->getIp}:{$this->public_port}/?directConnection=true";
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -39,14 +39,18 @@ class Subscription extends Model
|
|||||||
if (!$subscription) {
|
if (!$subscription) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$subscriptionPlanId = data_get($subscription,'stripe_plan_id');
|
$subscriptionPlanId = data_get($subscription, 'stripe_plan_id');
|
||||||
if (!$subscriptionPlanId) {
|
if (!$subscriptionPlanId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
$subscriptionInvoicePaid = data_get($subscription, 'stripe_invoice_paid');
|
||||||
|
if (!$subscriptionInvoicePaid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
$subscriptionConfigs = collect(config('subscription'));
|
$subscriptionConfigs = collect(config('subscription'));
|
||||||
$stripePlanId = null;
|
$stripePlanId = null;
|
||||||
$subscriptionConfigs->map(function ($value, $key) use ($subscriptionPlanId, &$stripePlanId) {
|
$subscriptionConfigs->map(function ($value, $key) use ($subscriptionPlanId, &$stripePlanId) {
|
||||||
if ($value === $subscriptionPlanId){
|
if ($value === $subscriptionPlanId) {
|
||||||
$stripePlanId = $key;
|
$stripePlanId = $key;
|
||||||
};
|
};
|
||||||
})->first();
|
})->first();
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class RouteServiceProvider extends ServiceProvider
|
|||||||
if ($request->path() === 'api/health') {
|
if ($request->path() === 'api/health') {
|
||||||
return Limit::perMinute(1000)->by($request->user()?->id ?: $request->ip());
|
return Limit::perMinute(1000)->by($request->user()?->id ?: $request->ip());
|
||||||
}
|
}
|
||||||
return Limit::perMinute(30)->by($request->user()?->id ?: $request->ip());
|
return Limit::perMinute(200)->by($request->user()?->id ?: $request->ip());
|
||||||
});
|
});
|
||||||
RateLimiter::for('5', function (Request $request) {
|
RateLimiter::for('5', function (Request $request) {
|
||||||
return Limit::perMinute(5)->by($request->user()?->id ?: $request->ip());
|
return Limit::perMinute(5)->by($request->user()?->id ?: $request->ip());
|
||||||
|
|||||||
@@ -212,13 +212,11 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
|||||||
$onlyPort = $ports[0];
|
$onlyPort = $ports[0];
|
||||||
}
|
}
|
||||||
$pull_request_id = data_get($preview, 'pull_request_id', 0);
|
$pull_request_id = data_get($preview, 'pull_request_id', 0);
|
||||||
// $container_name = generateApplicationContainerName($application, $pull_request_id);
|
|
||||||
$appId = $application->id;
|
$appId = $application->id;
|
||||||
if ($pull_request_id !== 0 && $pull_request_id !== null) {
|
if ($pull_request_id !== 0 && $pull_request_id !== null) {
|
||||||
$appId = $appId . '-pr-' . $pull_request_id;
|
$appId = $appId . '-pr-' . $pull_request_id;
|
||||||
}
|
}
|
||||||
$labels = collect([]);
|
$labels = collect([]);
|
||||||
$labels = $labels->merge(defaultLabels($appId, $application->uuid, $pull_request_id));
|
|
||||||
if ($application->fqdn) {
|
if ($application->fqdn) {
|
||||||
if ($pull_request_id !== 0) {
|
if ($pull_request_id !== 0) {
|
||||||
$domains = Str::of(data_get($preview, 'fqdn'))->explode(',');
|
$domains = Str::of(data_get($preview, 'fqdn'))->explode(',');
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ use App\Models\Application;
|
|||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
use App\Models\StandaloneMariadb;
|
||||||
use App\Models\StandaloneMongodb;
|
use App\Models\StandaloneMongodb;
|
||||||
|
use App\Models\StandaloneMysql;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use App\Models\StandaloneRedis;
|
use App\Models\StandaloneRedis;
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
@@ -484,5 +486,18 @@ function queryResourcesByUuid(string $uuid)
|
|||||||
if ($redis) return $redis;
|
if ($redis) return $redis;
|
||||||
$mongodb = StandaloneMongodb::whereUuid($uuid)->first();
|
$mongodb = StandaloneMongodb::whereUuid($uuid)->first();
|
||||||
if ($mongodb) return $mongodb;
|
if ($mongodb) return $mongodb;
|
||||||
|
$mysql = StandaloneMysql::whereUuid($uuid)->first();
|
||||||
|
if ($mysql) return $mysql;
|
||||||
|
$mariadb = StandaloneMariadb::whereUuid($uuid)->first();
|
||||||
|
if ($mariadb) return $mariadb;
|
||||||
return $resource;
|
return $resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateDeployWebhook($resource) {
|
||||||
|
$baseUrl = base_url();
|
||||||
|
$api = Url::fromString($baseUrl) . '/api/v1';
|
||||||
|
$endpoint = '/deploy';
|
||||||
|
$uuid = data_get($resource, 'uuid');
|
||||||
|
$url = $api . $endpoint . "?uuid=$uuid&force=false";
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ function allowedPathsForInvalidAccounts() {
|
|||||||
return [
|
return [
|
||||||
'logout',
|
'logout',
|
||||||
'verify',
|
'verify',
|
||||||
|
'force-password-reset',
|
||||||
|
'livewire/message/force-password-reset',
|
||||||
'livewire/message/verify-email',
|
'livewire/message/verify-email',
|
||||||
'livewire/message/help'
|
'livewire/message/help'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"laravel/ui": "^4.2",
|
"laravel/ui": "^4.2",
|
||||||
"lcobucci/jwt": "^5.0.0",
|
"lcobucci/jwt": "^5.0.0",
|
||||||
"league/flysystem-aws-s3-v3": "^3.0",
|
"league/flysystem-aws-s3-v3": "^3.0",
|
||||||
|
"league/flysystem-sftp-v3": "^3.0",
|
||||||
"livewire/livewire": "^v2.12.3",
|
"livewire/livewire": "^v2.12.3",
|
||||||
"lorisleiva/laravel-actions": "^2.7",
|
"lorisleiva/laravel-actions": "^2.7",
|
||||||
"masmerise/livewire-toaster": "^1.2",
|
"masmerise/livewire-toaster": "^1.2",
|
||||||
|
|||||||
62
composer.lock
generated
62
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "de2c45be3f03d43430549d963778dc4a",
|
"content-hash": "21ed976753483557403be75318585442",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-crt-php",
|
"name": "aws/aws-crt-php",
|
||||||
@@ -2938,6 +2938,66 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-08-30T10:23:59+00:00"
|
"time": "2023-08-30T10:23:59+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "league/flysystem-sftp-v3",
|
||||||
|
"version": "3.16.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/flysystem-sftp-v3.git",
|
||||||
|
"reference": "1ba682def8e87fd7fa00883629553c0200d2e974"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/flysystem-sftp-v3/zipball/1ba682def8e87fd7fa00883629553c0200d2e974",
|
||||||
|
"reference": "1ba682def8e87fd7fa00883629553c0200d2e974",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"league/flysystem": "^3.0.14",
|
||||||
|
"league/mime-type-detection": "^1.0.0",
|
||||||
|
"php": "^8.0.2",
|
||||||
|
"phpseclib/phpseclib": "^3.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\Flysystem\\PhpseclibV3\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Frank de Jonge",
|
||||||
|
"email": "info@frankdejonge.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "SFTP filesystem adapter for Flysystem.",
|
||||||
|
"keywords": [
|
||||||
|
"Flysystem",
|
||||||
|
"file",
|
||||||
|
"files",
|
||||||
|
"filesystem",
|
||||||
|
"sftp"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/thephpleague/flysystem-sftp-v3/issues",
|
||||||
|
"source": "https://github.com/thephpleague/flysystem-sftp-v3/tree/3.16.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://ecologi.com/frankdejonge",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/frankdejonge",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-08-30T10:25:05+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "league/mime-type-detection",
|
"name": "league/mime-type-detection",
|
||||||
"version": "1.13.0",
|
"version": "1.13.0",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.100',
|
'release' => '4.0.0-beta.106',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.100';
|
return '4.0.0-beta.106';
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('environment_variables', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_shown_once')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('environment_variables', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_shown_once');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
<div>Location: {{ data_get($execution, 'filename', 'N/A') }}</div>
|
<div>Location: {{ data_get($execution, 'filename', 'N/A') }}</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
|
@if (data_get($execution, 'status') === 'success')
|
||||||
{{-- @if (data_get($execution, 'status') !== 'failed') --}}
|
<x-forms.button class=" hover:bg-coolgray-400"
|
||||||
{{-- <x-forms.button class="bg-coollabs-100 hover:bg-coollabs" wire:click="download">Download</x-forms.button> --}}
|
wire:click="download({{ data_get($execution, 'id') }})">Download</x-forms.button>
|
||||||
{{-- @endif --}}
|
@endif
|
||||||
<x-forms.button isError onclick="sure({{ data_get($execution, 'id') }})">Delete</x-forms.button>
|
<x-forms.button isError onclick="sure({{ data_get($execution, 'id') }})">Delete</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -4,16 +4,25 @@
|
|||||||
<div class="flex h-full pt-6">
|
<div class="flex h-full pt-6">
|
||||||
<div class="flex flex-col items-start gap-4 min-w-fit">
|
<div class="flex flex-col items-start gap-4 min-w-fit">
|
||||||
<a target="_blank" href="{{ $service->documentation() }}">Documentation <x-external-link /></a>
|
<a target="_blank" href="{{ $service->documentation() }}">Documentation <x-external-link /></a>
|
||||||
<a :class="activeTab === 'service-stack' && 'text-white'" @click.prevent="activeTab = 'service-stack';
|
<a :class="activeTab === 'service-stack' && 'text-white'"
|
||||||
window.location.hash = 'service-stack'" href="#">Service Stack</a>
|
@click.prevent="activeTab = 'service-stack';
|
||||||
<a :class="activeTab === 'storages' && 'text-white'" @click.prevent="activeTab = 'storages';
|
window.location.hash = 'service-stack'"
|
||||||
window.location.hash = 'storages'" href="#">Storages</a>
|
href="#">Service Stack</a>
|
||||||
|
<a :class="activeTab === 'storages' && 'text-white'"
|
||||||
|
@click.prevent="activeTab = 'storages';
|
||||||
|
window.location.hash = 'storages'"
|
||||||
|
href="#">Storages</a>
|
||||||
|
<a :class="activeTab === 'webhooks' && 'text-white'"
|
||||||
|
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
|
||||||
|
</a>
|
||||||
<a :class="activeTab === 'environment-variables' && 'text-white'"
|
<a :class="activeTab === 'environment-variables' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
|
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
|
||||||
href="#">Environment
|
href="#">Environment
|
||||||
Variables</a>
|
Variables</a>
|
||||||
<a :class="activeTab === 'danger' && 'text-white'" @click.prevent="activeTab = 'danger';
|
<a :class="activeTab === 'danger' && 'text-white'"
|
||||||
window.location.hash = 'danger'" href="#">Danger Zone
|
@click.prevent="activeTab = 'danger';
|
||||||
|
window.location.hash = 'danger'"
|
||||||
|
href="#">Danger Zone
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full pl-8">
|
<div class="w-full pl-8">
|
||||||
@@ -100,7 +109,9 @@
|
|||||||
@foreach ($databases as $database)
|
@foreach ($databases as $database)
|
||||||
<livewire:project.service.storage wire:key="database-{{ $database->id }}" :resource="$database" />
|
<livewire:project.service.storage wire:key="database-{{ $database->id }}" :resource="$database" />
|
||||||
@endforeach
|
@endforeach
|
||||||
|
</div>
|
||||||
|
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||||
|
<livewire:project.shared.webhooks :resource="$service" />
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||||
|
|||||||
@@ -28,8 +28,7 @@
|
|||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
<form wire:submit.prevent='saveVariables(false)' class="flex flex-col gap-2">
|
<form wire:submit.prevent='saveVariables(false)' class="flex flex-col gap-2">
|
||||||
<x-forms.textarea rows=25 class="whitespace-pre-wrap"
|
<x-forms.textarea rows=25 class="whitespace-pre-wrap" id="variables"></x-forms.textarea>
|
||||||
id="variables"></x-forms.textarea>
|
|
||||||
<x-forms.button type="submit" class="btn btn-primary">Save</x-forms.button>
|
<x-forms.button type="submit" class="btn btn-primary">Save</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
@if ($showPreview)
|
@if ($showPreview)
|
||||||
|
|||||||
@@ -6,36 +6,57 @@
|
|||||||
</x-slot:modalBody>
|
</x-slot:modalBody>
|
||||||
</x-modal>
|
</x-modal>
|
||||||
<form wire:submit.prevent='submit' class="flex flex-col items-center gap-2 xl:flex-row">
|
<form wire:submit.prevent='submit' class="flex flex-col items-center gap-2 xl:flex-row">
|
||||||
@if ($isDisabled)
|
@if ($isLocked)
|
||||||
|
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||||
|
<path d="M5 13a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-6z" />
|
||||||
|
<path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0-2 0m-3-5V7a4 4 0 1 1 8 0v4" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
<x-forms.input disabled id="env.key" />
|
<x-forms.input disabled id="env.key" />
|
||||||
<x-forms.input disabled type="password" id="env.value" />
|
|
||||||
@if ($type !== 'service')
|
|
||||||
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
|
|
||||||
@endif
|
|
||||||
@else
|
@else
|
||||||
<x-forms.input id="env.key" />
|
@if ($isDisabled)
|
||||||
<x-forms.input type="password" id="env.value" />
|
<x-forms.input disabled id="env.key" />
|
||||||
@if ($type !== 'service')
|
<x-forms.input disabled type="password" id="env.value" />
|
||||||
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
|
@if ($type !== 'service')
|
||||||
|
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
<x-forms.input id="env.key" />
|
||||||
|
<x-forms.input type="password" id="env.value" />
|
||||||
|
@if ($type !== 'service')
|
||||||
|
<x-forms.checkbox instantSave id="env.is_build_time" label="Build Variable?" />
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@if ($isDisabled)
|
@if ($isLocked)
|
||||||
<x-forms.button disabled type="submit">
|
|
||||||
Update
|
|
||||||
</x-forms.button>
|
|
||||||
<x-forms.button disabled isError isModal modalId="{{ $modalId }}">
|
|
||||||
Delete
|
|
||||||
</x-forms.button>
|
|
||||||
@else
|
|
||||||
<x-forms.button type="submit">
|
|
||||||
Update
|
|
||||||
</x-forms.button>
|
|
||||||
<x-forms.button isError isModal modalId="{{ $modalId }}">
|
<x-forms.button isError isModal modalId="{{ $modalId }}">
|
||||||
Delete
|
Delete
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
|
@else
|
||||||
|
@if ($isDisabled)
|
||||||
|
<x-forms.button disabled type="submit">
|
||||||
|
Update
|
||||||
|
</x-forms.button>
|
||||||
|
<x-forms.button wire:click='lock'>
|
||||||
|
Lock
|
||||||
|
</x-forms.button>
|
||||||
|
<x-forms.button disabled isError isModal modalId="{{ $modalId }}">
|
||||||
|
Delete
|
||||||
|
</x-forms.button>
|
||||||
|
@else
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Update
|
||||||
|
</x-forms.button>
|
||||||
|
<x-forms.button wire:click='lock'>
|
||||||
|
Lock
|
||||||
|
</x-forms.button>
|
||||||
|
<x-forms.button isError isModal modalId="{{ $modalId }}">
|
||||||
|
Delete
|
||||||
|
</x-forms.button>
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
10
resources/views/livewire/project/shared/webhooks.blade.php
Normal file
10
resources/views/livewire/project/shared/webhooks.blade.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<h2>Webhooks</h2>
|
||||||
|
<x-helper
|
||||||
|
helper="For more details goto our <a class='text-white underline' href='https://coolify.io/docs/api-endpoints' target='_blank'>docs</a>." />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<x-forms.input readonly label="Deploy Webhook (auth required)" id="deploywebhook"></x-forms.input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
<a :class="activeTab === 'storages' && 'text-white'"
|
<a :class="activeTab === 'storages' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
|
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
|
||||||
</a>
|
</a>
|
||||||
|
<a :class="activeTab === 'webhooks' && 'text-white'"
|
||||||
|
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
|
||||||
|
</a>
|
||||||
@if ($application->git_based())
|
@if ($application->git_based())
|
||||||
<a :class="activeTab === 'previews' && 'text-white'"
|
<a :class="activeTab === 'previews' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Preview
|
@click.prevent="activeTab = 'previews'; window.location.hash = 'previews'" href="#">Preview
|
||||||
@@ -57,6 +60,9 @@
|
|||||||
<div x-cloak x-show="activeTab === 'storages'">
|
<div x-cloak x-show="activeTab === 'storages'">
|
||||||
<livewire:project.service.storage :resource="$application" />
|
<livewire:project.service.storage :resource="$application" />
|
||||||
</div>
|
</div>
|
||||||
|
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||||
|
<livewire:project.shared.webhooks :resource="$application" />
|
||||||
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'previews'">
|
<div x-cloak x-show="activeTab === 'previews'">
|
||||||
<livewire:project.application.previews :application="$application" />
|
<livewire:project.application.previews :application="$application" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
window.location.hash = 'storages'"
|
window.location.hash = 'storages'"
|
||||||
href="#">Storages
|
href="#">Storages
|
||||||
</a>
|
</a>
|
||||||
|
<a :class="activeTab === 'webhooks' && 'text-white'"
|
||||||
|
@click.prevent="activeTab = 'webhooks'; window.location.hash = 'webhooks'" href="#">Webhooks
|
||||||
|
</a>
|
||||||
<a :class="activeTab === 'resource-limits' && 'text-white'"
|
<a :class="activeTab === 'resource-limits' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'resource-limits';
|
@click.prevent="activeTab = 'resource-limits';
|
||||||
window.location.hash = 'resource-limits'"
|
window.location.hash = 'resource-limits'"
|
||||||
@@ -65,6 +68,9 @@
|
|||||||
<div x-cloak x-show="activeTab === 'storages'">
|
<div x-cloak x-show="activeTab === 'storages'">
|
||||||
<livewire:project.service.storage :resource="$database" />
|
<livewire:project.service.storage :resource="$database" />
|
||||||
</div>
|
</div>
|
||||||
|
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||||
|
<livewire:project.shared.webhooks :resource="$database" />
|
||||||
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'resource-limits'">
|
<div x-cloak x-show="activeTab === 'resource-limits'">
|
||||||
<livewire:project.shared.resource-limits :resource="$database" />
|
<livewire:project.shared.resource-limits :resource="$database" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Actions\Database\StartMariadb;
|
||||||
use App\Actions\Database\StartMongodb;
|
use App\Actions\Database\StartMongodb;
|
||||||
|
use App\Actions\Database\StartMysql;
|
||||||
use App\Actions\Database\StartPostgresql;
|
use App\Actions\Database\StartPostgresql;
|
||||||
use App\Actions\Database\StartRedis;
|
use App\Actions\Database\StartRedis;
|
||||||
use App\Actions\Service\StartService;
|
use App\Actions\Service\StartService;
|
||||||
@@ -32,7 +34,6 @@ Route::group([
|
|||||||
$teamId = data_get($token, 'team_id');
|
$teamId = data_get($token, 'team_id');
|
||||||
$uuid = $request->query->get('uuid');
|
$uuid = $request->query->get('uuid');
|
||||||
$force = $request->query->get('force') ?? false;
|
$force = $request->query->get('force') ?? false;
|
||||||
|
|
||||||
if (is_null($teamId)) {
|
if (is_null($teamId)) {
|
||||||
return response()->json(['error' => 'Invalid token.'], 400);
|
return response()->json(['error' => 'Invalid token.'], 400);
|
||||||
}
|
}
|
||||||
@@ -50,29 +51,56 @@ Route::group([
|
|||||||
);
|
);
|
||||||
return response()->json(['message' => 'Deployment queued.'], 200);
|
return response()->json(['message' => 'Deployment queued.'], 200);
|
||||||
} else if ($type === 'App\Models\StandalonePostgresql') {
|
} else if ($type === 'App\Models\StandalonePostgresql') {
|
||||||
|
if (str($resource->status)->startsWith('running')) {
|
||||||
|
return response()->json(['message' => 'Database already running.'], 200);
|
||||||
|
}
|
||||||
StartPostgresql::run($resource);
|
StartPostgresql::run($resource);
|
||||||
$resource->update([
|
$resource->update([
|
||||||
'started_at' => now(),
|
'started_at' => now(),
|
||||||
]);
|
]);
|
||||||
return response()->json(['message' => 'Database started.'], 200);
|
return response()->json(['message' => 'Database started.'], 200);
|
||||||
} else if ($type === 'App\Models\StandaloneRedis') {
|
} else if ($type === 'App\Models\StandaloneRedis') {
|
||||||
|
if (str($resource->status)->startsWith('running')) {
|
||||||
|
return response()->json(['message' => 'Database already running.'], 200);
|
||||||
|
}
|
||||||
StartRedis::run($resource);
|
StartRedis::run($resource);
|
||||||
$resource->update([
|
$resource->update([
|
||||||
'started_at' => now(),
|
'started_at' => now(),
|
||||||
]);
|
]);
|
||||||
return response()->json(['message' => 'Database started.'], 200);
|
return response()->json(['message' => 'Database started.'], 200);
|
||||||
} else if ($type === 'App\Models\StandaloneMongodb') {
|
} else if ($type === 'App\Models\StandaloneMongodb') {
|
||||||
|
if (str($resource->status)->startsWith('running')) {
|
||||||
|
return response()->json(['message' => 'Database already running.'], 200);
|
||||||
|
}
|
||||||
StartMongodb::run($resource);
|
StartMongodb::run($resource);
|
||||||
$resource->update([
|
$resource->update([
|
||||||
'started_at' => now(),
|
'started_at' => now(),
|
||||||
]);
|
]);
|
||||||
return response()->json(['message' => 'Database started.'], 200);
|
return response()->json(['message' => 'Database started.'], 200);
|
||||||
}else if ($type === 'App\Models\Service') {
|
} else if ($type === 'App\Models\StandaloneMysql') {
|
||||||
|
if (str($resource->status)->startsWith('running')) {
|
||||||
|
return response()->json(['message' => 'Database already running.'], 200);
|
||||||
|
}
|
||||||
|
StartMysql::run($resource);
|
||||||
|
$resource->update([
|
||||||
|
'started_at' => now(),
|
||||||
|
]);
|
||||||
|
return response()->json(['message' => 'Database started.'], 200);
|
||||||
|
} else if ($type === 'App\Models\StandaloneMariadb') {
|
||||||
|
if (str($resource->status)->startsWith('running')) {
|
||||||
|
return response()->json(['message' => 'Database already running.'], 200);
|
||||||
|
}
|
||||||
|
StartMariadb::run($resource);
|
||||||
|
$resource->update([
|
||||||
|
'started_at' => now(),
|
||||||
|
]);
|
||||||
|
return response()->json(['message' => 'Database started.'], 200);
|
||||||
|
} else if ($type === 'App\Models\Service') {
|
||||||
StartService::run($resource);
|
StartService::run($resource);
|
||||||
return response()->json(['message' => 'Service started.'], 200);
|
return response()->json(['message' => 'Service started. It could take a while, be patient.'], 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return response()->json(['error' => 'No resource found.'], 404);
|
return response()->json(['error' => "No resource found with {$uuid}."], 404);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ Route::post('/source/github/events', function () {
|
|||||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||||
if ($found) {
|
if ($found) {
|
||||||
$found->delete();
|
$found->delete();
|
||||||
$container_name = generateApplicationContainerName($application,$pull_request_id);
|
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||||
// ray('Stopping container: ' . $container_name);
|
// ray('Stopping container: ' . $container_name);
|
||||||
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
||||||
return response('Preview Deployment closed.');
|
return response('Preview Deployment closed.');
|
||||||
@@ -288,6 +288,14 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
'stripe_invoice_paid' => true,
|
'stripe_invoice_paid' => true,
|
||||||
]);
|
]);
|
||||||
break;
|
break;
|
||||||
|
case 'payment_intent.payment_failed':
|
||||||
|
$customerId = data_get($data, 'customer');
|
||||||
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
|
$subscription->update([
|
||||||
|
'stripe_invoice_paid' => false,
|
||||||
|
]);
|
||||||
|
send_internal_notification('Subscription payment failed: ' . $subscription->team->id);
|
||||||
|
break;
|
||||||
case 'customer.subscription.updated':
|
case 'customer.subscription.updated':
|
||||||
$customerId = data_get($data, 'customer');
|
$customerId = data_get($data, 'customer');
|
||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
|
||||||
@@ -305,11 +313,11 @@ Route::post('/payments/stripe/events', function () {
|
|||||||
'stripe_plan_id' => $planId,
|
'stripe_plan_id' => $planId,
|
||||||
'stripe_cancel_at_period_end' => $cancelAtPeriodEnd,
|
'stripe_cancel_at_period_end' => $cancelAtPeriodEnd,
|
||||||
]);
|
]);
|
||||||
if ($status === 'paused') {
|
if ($status === 'paused' || $status === 'incomplete_expired') {
|
||||||
$subscription->update([
|
$subscription->update([
|
||||||
'stripe_invoice_paid' => false,
|
'stripe_invoice_paid' => false,
|
||||||
]);
|
]);
|
||||||
send_internal_notification('Subscription paused for team: ' . $subscription->team->id);
|
send_internal_notification('Subscription paused or incomplete for team: ' . $subscription->team->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trial ended but subscribed, reactive servers
|
// Trial ended but subscribed, reactive servers
|
||||||
|
|||||||
@@ -14,3 +14,5 @@ services:
|
|||||||
- APPSMITH_SMART_LOOK_ID=
|
- APPSMITH_SMART_LOOK_ID=
|
||||||
volumes:
|
volumes:
|
||||||
- stacks-data:/appsmith-stacks
|
- stacks-data:/appsmith-stacks
|
||||||
|
healthcheck:
|
||||||
|
test: ["NONE"]
|
||||||
|
|||||||
16
templates/compose/dashboard.yaml
Normal file
16
templates/compose/dashboard.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# documentation: https://github.com/phntxx/dashboard/wiki/Installation#installation-using-docker
|
||||||
|
# slogan: A dashboard. Inspired by SUI, it offers simple customization through JSON-files and a handy search bar to help you browse the internet more efficiently.
|
||||||
|
# tags: dashboard, web, search, bookmarks
|
||||||
|
|
||||||
|
services:
|
||||||
|
dashboard:
|
||||||
|
image: phntxx/dashboard:latest
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_DASHBOARD
|
||||||
|
volumes:
|
||||||
|
- dashboard-data:/app/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8080"]
|
||||||
|
interval: 2s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 15
|
||||||
21
templates/compose/emby.yaml
Normal file
21
templates/compose/emby.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# documentation: https://emby.media/support/articles/Home.html
|
||||||
|
# slogan: A media server software that allows you to organize, stream, and access your multimedia content effortlessly, making it easy to enjoy your favorite movies, TV shows, music, and more.
|
||||||
|
# tags: media, server, movies, tv, music
|
||||||
|
|
||||||
|
services:
|
||||||
|
emby:
|
||||||
|
image: lscr.io/linuxserver/emby:latest
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_EMBY
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=Europe/Madrid
|
||||||
|
volumes:
|
||||||
|
- emby-config:/config
|
||||||
|
- emby-tvshows:/tvshows
|
||||||
|
- emby-movies:/movies
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8096"]
|
||||||
|
interval: 2s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 15
|
||||||
19
templates/compose/embystat.yaml
Normal file
19
templates/compose/embystat.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# documentation: https://github.com/mregni/EmbyStat/wiki/docker
|
||||||
|
# slogan: EmyStat is an open-source, self-hosted web analytics tool, designed to provide insight into website traffic and user behavior, of your local Emby deployement, all within your control.
|
||||||
|
# tags: media, server, movies, tv, music
|
||||||
|
|
||||||
|
services:
|
||||||
|
embystat:
|
||||||
|
image: lscr.io/linuxserver/embystat:latest
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_EMBYSTAT
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=Europe/Madrid
|
||||||
|
volumes:
|
||||||
|
- embystat-config:/config
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:6555"]
|
||||||
|
interval: 2s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 15
|
||||||
@@ -29,5 +29,5 @@ services:
|
|||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 20s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
|||||||
40
templates/compose/grafana-with-postgresql.yaml
Normal file
40
templates/compose/grafana-with-postgresql.yaml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# documentation: https://grafana.com/docs/grafana/latest/installation/docker/
|
||||||
|
# slogan: Grafana is the open source analytics & monitoring solution for every database.
|
||||||
|
# tags: grafana,analytics,monitoring,dashboard
|
||||||
|
|
||||||
|
services:
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana-oss
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_GRAFANA
|
||||||
|
- GF_SERVER_ROOT_URL=${SERVICE_FQDN_GRAFANA}
|
||||||
|
- GF_SERVER_DOMAIN=${SERVICE_FQDN_GRAFANA}
|
||||||
|
- GF_SECURITY_ADMIN_PASSWORD=${SERVICE_PASSWORD_GRAFANA}
|
||||||
|
- GF_DATABASE_TYPE=postgres
|
||||||
|
- GF_DATABASE_HOST=postgresql
|
||||||
|
- GF_DATABASE_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- GF_DATABASE_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||||
|
- GF_DATABASE_NAME=${POSTGRES_DB:-grafana}
|
||||||
|
volumes:
|
||||||
|
- grafana-data:/var/lib/grafana
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
|
depends_on:
|
||||||
|
- postgresql
|
||||||
|
postgresql:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
volumes:
|
||||||
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB:-grafana}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
19
templates/compose/grafana.yaml
Normal file
19
templates/compose/grafana.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# documentation: https://grafana.com/docs/grafana/latest/installation/docker/
|
||||||
|
# slogan: Grafana is the open source analytics & monitoring solution for every database.
|
||||||
|
# tags: grafana,analytics,monitoring,dashboard
|
||||||
|
|
||||||
|
services:
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana-oss
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_GRAFANA
|
||||||
|
- GF_SERVER_ROOT_URL=${SERVICE_FQDN_GRAFANA}
|
||||||
|
- GF_SERVER_DOMAIN=${SERVICE_FQDN_GRAFANA}
|
||||||
|
- GF_SECURITY_ADMIN_PASSWORD=${SERVICE_PASSWORD_GRAFANA}
|
||||||
|
volumes:
|
||||||
|
- grafana-data:/var/lib/grafana
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
19
templates/compose/grocy.yaml
Normal file
19
templates/compose/grocy.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# documentation: https://github.com/grocy/grocy
|
||||||
|
# slogan: Grocy is a self-hosted, web-based household management and grocery list application, designed to simplify your household chores and grocery shopping.
|
||||||
|
# tags: groceries, household, management, grocery, shopping
|
||||||
|
|
||||||
|
services:
|
||||||
|
grocy:
|
||||||
|
image: lscr.io/linuxserver/grocy:latest
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_GROCY
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=Europe/Madrid
|
||||||
|
volumes:
|
||||||
|
- grocy-config:/config
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:80"]
|
||||||
|
interval: 2s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 15
|
||||||
32
templates/compose/mattermost.yaml
Normal file
32
templates/compose/mattermost.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# ignore: true
|
||||||
|
# documentation: https://docs.mattermost.com
|
||||||
|
# slogan: Mattermost is an open source, self-hosted Slack-alternative.
|
||||||
|
# tags: mattermost,slack,alternative
|
||||||
|
|
||||||
|
services:
|
||||||
|
mattermost:
|
||||||
|
image: mattermost/mattermost-team-edition:9.1
|
||||||
|
volumes:
|
||||||
|
- mattermost-data:/mattermost
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_MATTERMOST
|
||||||
|
- TZ=${TZ:-UTC}
|
||||||
|
- MM_SQLSETTINGS_DRIVERNAME=postgres
|
||||||
|
- MM_SQLSETTINGS_DATASOURCE=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgres:5432/$POSTGRES_DB?sslmode=disable&connect_timeout=10
|
||||||
|
- MM_BLEVESETTINGS_INDEXDIR=/mattermost/bleve-indexes
|
||||||
|
- MM_SERVICESETTINGS_SITEURL=$SERVICE_FQDN_MATTERMOST
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
volumes:
|
||||||
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB:-mattermost}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
38
templates/compose/n8n-with-postgresql.yaml
Normal file
38
templates/compose/n8n-with-postgresql.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# documentation: https://docs.n8n.io/hosting/
|
||||||
|
# slogan: n8n is an extendable workflow automation tool which enables you to connect anything to everything via its open, fair-code model.
|
||||||
|
# tags: n8n,workflow,automation,open,source,low,code
|
||||||
|
|
||||||
|
services:
|
||||||
|
n8n:
|
||||||
|
image: docker.n8n.io/n8nio/n8n
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_N8N
|
||||||
|
- N8N_EDITOR_BASE_URL=${SERVICE_FQDN_N8N}
|
||||||
|
- N8N_HOST=${SERVICE_FQDN_N8N}
|
||||||
|
- GENERIC_TIMEZONE="Europe/Berlin"
|
||||||
|
- TZ="Europe/Berlin"
|
||||||
|
- DB_TYPE=postgresdb
|
||||||
|
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB:-umami}
|
||||||
|
- DB_POSTGRESDB_HOST=postgresql
|
||||||
|
- DB_POSTGRESDB_PORT=5432
|
||||||
|
- DB_POSTGRESDB_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- DB_POSTGRESDB_SCHEMA=public
|
||||||
|
- DB_POSTGRESDB_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||||
|
volumes:
|
||||||
|
- n8n-data:/home/node/.n8n
|
||||||
|
depends_on:
|
||||||
|
- postgresql
|
||||||
|
postgresql:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
volumes:
|
||||||
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB:-umami}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
15
templates/compose/n8n.yaml
Normal file
15
templates/compose/n8n.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# documentation: https://docs.n8n.io/hosting/
|
||||||
|
# slogan: n8n is an extendable workflow automation tool which enables you to connect anything to everything via its open, fair-code model.
|
||||||
|
# tags: n8n,workflow,automation,open,source,low,code
|
||||||
|
|
||||||
|
services:
|
||||||
|
n8n:
|
||||||
|
image: docker.n8n.io/n8nio/n8n
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_N8N
|
||||||
|
- N8N_EDITOR_BASE_URL=${SERVICE_FQDN_N8N}
|
||||||
|
- N8N_HOST=${SERVICE_FQDN_N8N}
|
||||||
|
- GENERIC_TIMEZONE="Europe/Berlin"
|
||||||
|
- TZ="Europe/Berlin"
|
||||||
|
volumes:
|
||||||
|
- n8n-data:/home/node/.n8n
|
||||||
16
templates/compose/nocodb.yaml
Normal file
16
templates/compose/nocodb.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# documentation: https://docs.nocodb.com/
|
||||||
|
# slogan: NocoDB is an open source Airtable alternative. Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart-spreadsheet.
|
||||||
|
# tags: nocodb,airtable,mysql,postgresql,sqlserver,sqlite,mariadb
|
||||||
|
|
||||||
|
services:
|
||||||
|
nocodb:
|
||||||
|
image: nocodb/nocodb
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_NOCODB
|
||||||
|
volumes:
|
||||||
|
- nocodb-data:/usr/app/data/
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
19
templates/compose/openblocks.yaml
Normal file
19
templates/compose/openblocks.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# documentation: https://docs.openblocks.dev/self-hosting
|
||||||
|
# slogan: OpenBlocks is a self-hosted, open-source, low-code platform for building internal tools.
|
||||||
|
# tags: openblocks,low,code,platform,open,source,low,code
|
||||||
|
|
||||||
|
services:
|
||||||
|
openblocks:
|
||||||
|
image: openblocksdev/openblocks-ce
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_OPENBLOCKS
|
||||||
|
- ENABLE_USER_SIGN_UP=${ENABLE_USER_SIGN_UP:-true}
|
||||||
|
- ENCRYPTION_PASSWORD=$SERVICE_PASSWORD_ENCRYPTION
|
||||||
|
- ENCRYPTION_SALT=$SERVICE_PASSWORD_SALT
|
||||||
|
volumes:
|
||||||
|
- openblocks-data:/openblocks-stacks
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# documentation: https://github.com/schlagmichdoch/PairDrop/blob/master/docs/faq.md
|
# documentation: https://github.com/schlagmichdoch/PairDrop
|
||||||
# slogan: Pairdrop is a self-hosted file sharing and collaboration platform, offering secure file sharing and collaboration capabilities for efficient teamwork.
|
# slogan: Pairdrop is a self-hosted file sharing and collaboration platform, offering secure file sharing and collaboration capabilities for efficient teamwork.
|
||||||
# tags: file, sharing, collaboration, teamwork
|
# tags: file, sharing, collaboration, teamwork
|
||||||
|
|
||||||
|
|||||||
11
templates/compose/pocketbase.yaml
Normal file
11
templates/compose/pocketbase.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# documentation: https://pocketbase.io/docs/
|
||||||
|
# slogan: Open Source backend for your next SaaS and Mobile app in 1 file
|
||||||
|
# tags: pocketbase,backend,saas,mobile,api
|
||||||
|
|
||||||
|
services:
|
||||||
|
pocketbase:
|
||||||
|
image: ghcr.io/coollabsio/pocketbase:latest
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_POCKETBASE
|
||||||
|
volumes:
|
||||||
|
- pocketbase-data:/app/pb_data
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# documentation: https://github.com/RobinLinus/snapdrop/blob/master/docs/faq.md
|
# documentation: https://github.com/RobinLinus/snapdrop
|
||||||
# slogan: A self-hosted file-sharing service for secure and convenient file transfers, whether on a local network or the internet.
|
# slogan: A self-hosted file-sharing service for secure and convenient file transfers, whether on a local network or the internet.
|
||||||
# tags: file, sharing, transfer, local, network, internet
|
# tags: file, sharing, transfer, local, network, internet
|
||||||
|
|
||||||
|
|||||||
@@ -24,5 +24,5 @@ services:
|
|||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 20s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# documentation: https://wordpress.org/documentation/
|
# documentation: https://wordpress.org/documentation/
|
||||||
# slogan: "WordPress is open source software you can use to create a beautiful website, blog, or app."
|
# slogan: WordPress with MariaDB. Wordpress is open source software you can use to create a beautiful website, blog, or app.
|
||||||
# tags: cms, blog, content, management, mariadb
|
# tags: cms, blog, content, management, mariadb
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# documentation: https://wordpress.org/documentation/
|
# documentation: https://wordpress.org/documentation/
|
||||||
# slogan: "WordPress is open source software you can use to create a beautiful website, blog, or app."
|
# slogan: WordPress with MySQL. Wordpress is open source software you can use to create a beautiful website, blog, or app.
|
||||||
# tags: cms, blog, content, management, mysql
|
# tags: cms, blog, content, management, mysql
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# documentation: https://wordpress.org/documentation/
|
# documentation: https://wordpress.org/documentation/
|
||||||
# slogan: "WordPress is open source software you can use to create a beautiful website, blog, or app."
|
# slogan: WordPress with external database. Wordpress is open source software you can use to create a beautiful website, blog, or app.
|
||||||
# tags: cms, blog, content, management
|
# tags: cms, blog, content, management
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"appsmith": {
|
"appsmith": {
|
||||||
"documentation": "https:\/\/docs.appsmith.com",
|
"documentation": "https:\/\/docs.appsmith.com",
|
||||||
"slogan": "Appsmith is an open-source, self-hosted application development platform that enables you to build powerful web applications with ease.",
|
"slogan": "Appsmith is an open-source, self-hosted application development platform that enables you to build powerful web applications with ease.",
|
||||||
"compose": "c2VydmljZXM6CiAgYXBwc21pdGg6CiAgICBpbWFnZTogJ2luZGV4LmRvY2tlci5pby9hcHBzbWl0aC9hcHBzbWl0aC1jZTpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE4KICAgICAgLSBBUFBTTUlUSF9NQUlMX0VOQUJMRUQ9ZmFsc2UKICAgICAgLSBBUFBTTUlUSF9ESVNBQkxFX1RFTEVNRVRSWT10cnVlCiAgICAgIC0gQVBQU01JVEhfRElTQUJMRV9JTlRFUkNPTT10cnVlCiAgICAgIC0gQVBQU01JVEhfU0VOVFJZX0RTTj0KICAgICAgLSBBUFBTTUlUSF9TTUFSVF9MT09LX0lEPQogICAgdm9sdW1lczoKICAgICAgLSAnc3RhY2tzLWRhdGE6L2FwcHNtaXRoLXN0YWNrcycK",
|
"compose": "c2VydmljZXM6CiAgYXBwc21pdGg6CiAgICBpbWFnZTogJ2luZGV4LmRvY2tlci5pby9hcHBzbWl0aC9hcHBzbWl0aC1jZTpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE4KICAgICAgLSBBUFBTTUlUSF9NQUlMX0VOQUJMRUQ9ZmFsc2UKICAgICAgLSBBUFBTTUlUSF9ESVNBQkxFX1RFTEVNRVRSWT10cnVlCiAgICAgIC0gQVBQU01JVEhfRElTQUJMRV9JTlRFUkNPTT10cnVlCiAgICAgIC0gQVBQU01JVEhfU0VOVFJZX0RTTj0KICAgICAgLSBBUFBTTUlUSF9TTUFSVF9MT09LX0lEPQogICAgdm9sdW1lczoKICAgICAgLSAnc3RhY2tzLWRhdGE6L2FwcHNtaXRoLXN0YWNrcycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gTk9ORQo=",
|
||||||
"tags": [
|
"tags": [
|
||||||
"lowcode",
|
"lowcode",
|
||||||
"nocode",
|
"nocode",
|
||||||
@@ -44,6 +44,17 @@
|
|||||||
"collaboration"
|
"collaboration"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"documentation": "https:\/\/github.com\/phntxx\/dashboard\/wiki\/Installation#installation-using-docker",
|
||||||
|
"slogan": "A dashboard. Inspired by SUI, it offers simple customization through JSON-files and a handy search bar to help you browse the internet more efficiently.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgZGFzaGJvYXJkOgogICAgaW1hZ2U6ICdwaG50eHgvZGFzaGJvYXJkOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9EQVNIQk9BUkQKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Rhc2hib2FyZC1kYXRhOi9hcHAvZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo4MDgwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==",
|
||||||
|
"tags": [
|
||||||
|
"dashboard",
|
||||||
|
"web",
|
||||||
|
"search",
|
||||||
|
"bookmarks"
|
||||||
|
]
|
||||||
|
},
|
||||||
"dokuwiki": {
|
"dokuwiki": {
|
||||||
"documentation": "https:\/\/www.dokuwiki.org\/faq",
|
"documentation": "https:\/\/www.dokuwiki.org\/faq",
|
||||||
"slogan": "A lightweight and easy-to-use wiki platform for creating and managing documentation and knowledge bases with simplicity and flexibility.",
|
"slogan": "A lightweight and easy-to-use wiki platform for creating and managing documentation and knowledge bases with simplicity and flexibility.",
|
||||||
@@ -55,6 +66,30 @@
|
|||||||
"base"
|
"base"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"emby": {
|
||||||
|
"documentation": "https:\/\/emby.media\/support\/articles\/Home.html",
|
||||||
|
"slogan": "A media server software that allows you to organize, stream, and access your multimedia content effortlessly, making it easy to enjoy your favorite movies, TV shows, music, and more.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgZW1ieToKICAgIGltYWdlOiAnbHNjci5pby9saW51eHNlcnZlci9lbWJ5OmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9FTUJZCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gVFo9RXVyb3BlL01hZHJpZAogICAgdm9sdW1lczoKICAgICAgLSAnZW1ieS1jb25maWc6L2NvbmZpZycKICAgICAgLSAnZW1ieS10dnNob3dzOi90dnNob3dzJwogICAgICAtICdlbWJ5LW1vdmllczovbW92aWVzJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwOTYnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK",
|
||||||
|
"tags": [
|
||||||
|
"media",
|
||||||
|
"server",
|
||||||
|
"movies",
|
||||||
|
"tv",
|
||||||
|
"music"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"embystat": {
|
||||||
|
"documentation": "https:\/\/github.com\/mregni\/EmbyStat\/wiki\/docker",
|
||||||
|
"slogan": "EmyStat is an open-source, self-hosted web analytics tool, designed to provide insight into website traffic and user behavior, of your local Emby deployement, all within your control.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgZW1ieXN0YXQ6CiAgICBpbWFnZTogJ2xzY3IuaW8vbGludXhzZXJ2ZXIvZW1ieXN0YXQ6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0VNQllTVEFUCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gVFo9RXVyb3BlL01hZHJpZAogICAgdm9sdW1lczoKICAgICAgLSAnZW1ieXN0YXQtY29uZmlnOi9jb25maWcnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6NjU1NScKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQo=",
|
||||||
|
"tags": [
|
||||||
|
"media",
|
||||||
|
"server",
|
||||||
|
"movies",
|
||||||
|
"tv",
|
||||||
|
"music"
|
||||||
|
]
|
||||||
|
},
|
||||||
"fider": {
|
"fider": {
|
||||||
"documentation": "https:\/\/fider.io\/doc",
|
"documentation": "https:\/\/fider.io\/doc",
|
||||||
"slogan": "Fider is an open-source feedback platform for collecting and managing user feedback, helping you prioritize improvements to your products and services.",
|
"slogan": "Fider is an open-source feedback platform for collecting and managing user feedback, helping you prioritize improvements to your products and services.",
|
||||||
@@ -67,7 +102,7 @@
|
|||||||
"ghost": {
|
"ghost": {
|
||||||
"documentation": "https:\/\/ghost.org\/docs",
|
"documentation": "https:\/\/ghost.org\/docs",
|
||||||
"slogan": "Ghost is a popular open-source content management system (CMS) and blogging platform, known for its simplicity and focus on content creation.",
|
"slogan": "Ghost is a popular open-source content management system (CMS) and blogging platform, known for its simplicity and focus on content creation.",
|
||||||
"compose": "c2VydmljZXM6CiAgZ2hvc3Q6CiAgICBpbWFnZTogJ2dob3N0OjUnCiAgICB2b2x1bWVzOgogICAgICAtICdnaG9zdC1jb250ZW50LWRhdGE6L3Zhci9saWIvZ2hvc3QvY29udGVudCcKICAgIGVudmlyb25tZW50OgogICAgICAtIHVybD0kU0VSVklDRV9GUUROX0dIT1NUCiAgICAgIC0gZGF0YWJhc2VfX2NsaWVudD1teXNxbAogICAgICAtIGRhdGFiYXNlX19jb25uZWN0aW9uX19ob3N0PW15c3FsCiAgICAgIC0gZGF0YWJhc2VfX2Nvbm5lY3Rpb25fX3VzZXI9JFNFUlZJQ0VfVVNFUl9NWVNRTAogICAgICAtIGRhdGFiYXNlX19jb25uZWN0aW9uX19wYXNzd29yZD0kU0VSVklDRV9QQVNTV09SRF9NWVNRTAogICAgICAtICdkYXRhYmFzZV9fY29ubmVjdGlvbl9fZGF0YWJhc2U9JHtNWVNRTF9EQVRBQkFTRS1naG9zdH0nCiAgICBkZXBlbmRzX29uOgogICAgICBteXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogIG15c3FsOgogICAgaW1hZ2U6ICdteXNxbDo4LjAnCiAgICB2b2x1bWVzOgogICAgICAtICdnaG9zdC1teXNxbC1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01ZU1FMX1VTRVI9JHtTRVJWSUNFX1VTRVJfTVlTUUx9JwogICAgICAtICdNWVNRTF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUx9JwogICAgICAtICdNWVNRTF9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFfScKICAgICAgLSAnTVlTUUxfUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBteXNxbGFkbWluCiAgICAgICAgLSBwaW5nCiAgICAgICAgLSAnLWgnCiAgICAgICAgLSBsb2NhbGhvc3QKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCg==",
|
"compose": "c2VydmljZXM6CiAgZ2hvc3Q6CiAgICBpbWFnZTogJ2dob3N0OjUnCiAgICB2b2x1bWVzOgogICAgICAtICdnaG9zdC1jb250ZW50LWRhdGE6L3Zhci9saWIvZ2hvc3QvY29udGVudCcKICAgIGVudmlyb25tZW50OgogICAgICAtIHVybD0kU0VSVklDRV9GUUROX0dIT1NUCiAgICAgIC0gZGF0YWJhc2VfX2NsaWVudD1teXNxbAogICAgICAtIGRhdGFiYXNlX19jb25uZWN0aW9uX19ob3N0PW15c3FsCiAgICAgIC0gZGF0YWJhc2VfX2Nvbm5lY3Rpb25fX3VzZXI9JFNFUlZJQ0VfVVNFUl9NWVNRTAogICAgICAtIGRhdGFiYXNlX19jb25uZWN0aW9uX19wYXNzd29yZD0kU0VSVklDRV9QQVNTV09SRF9NWVNRTAogICAgICAtICdkYXRhYmFzZV9fY29ubmVjdGlvbl9fZGF0YWJhc2U9JHtNWVNRTF9EQVRBQkFTRS1naG9zdH0nCiAgICBkZXBlbmRzX29uOgogICAgICBteXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogIG15c3FsOgogICAgaW1hZ2U6ICdteXNxbDo4LjAnCiAgICB2b2x1bWVzOgogICAgICAtICdnaG9zdC1teXNxbC1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01ZU1FMX1VTRVI9JHtTRVJWSUNFX1VTRVJfTVlTUUx9JwogICAgICAtICdNWVNRTF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUx9JwogICAgICAtICdNWVNRTF9EQVRBQkFTRT0ke01ZU1FMX0RBVEFCQVNFfScKICAgICAgLSAnTVlTUUxfUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTVlTUUxST09UfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBteXNxbGFkbWluCiAgICAgICAgLSBwaW5nCiAgICAgICAgLSAnLWgnCiAgICAgICAgLSBsb2NhbGhvc3QKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||||
"tags": [
|
"tags": [
|
||||||
"cms",
|
"cms",
|
||||||
"blog",
|
"blog",
|
||||||
@@ -76,6 +111,40 @@
|
|||||||
"system"
|
"system"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"grafana-with-postgresql": {
|
||||||
|
"documentation": "https:\/\/grafana.com\/docs\/grafana\/latest\/installation\/docker\/",
|
||||||
|
"slogan": "Grafana is the open source analytics & monitoring solution for every database.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgZ3JhZmFuYToKICAgIGltYWdlOiBncmFmYW5hL2dyYWZhbmEtb3NzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fR1JBRkFOQQogICAgICAtICdHRl9TRVJWRVJfUk9PVF9VUkw9JHtTRVJWSUNFX0ZRRE5fR1JBRkFOQX0nCiAgICAgIC0gJ0dGX1NFUlZFUl9ET01BSU49JHtTRVJWSUNFX0ZRRE5fR1JBRkFOQX0nCiAgICAgIC0gJ0dGX1NFQ1VSSVRZX0FETUlOX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9HUkFGQU5BfScKICAgICAgLSBHRl9EQVRBQkFTRV9UWVBFPXBvc3RncmVzCiAgICAgIC0gR0ZfREFUQUJBU0VfSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gR0ZfREFUQUJBU0VfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gR0ZfREFUQUJBU0VfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSAnR0ZfREFUQUJBU0VfTkFNRT0ke1BPU1RHUkVTX0RCOi1ncmFmYW5hfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2dyYWZhbmEtZGF0YTovdmFyL2xpYi9ncmFmYW5hJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjMwMDAvYXBpL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgLSBwb3N0Z3Jlc3FsCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWdyYWZhbmF9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||||
|
"tags": [
|
||||||
|
"grafana",
|
||||||
|
"analytics",
|
||||||
|
"monitoring",
|
||||||
|
"dashboard"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"grafana": {
|
||||||
|
"documentation": "https:\/\/grafana.com\/docs\/grafana\/latest\/installation\/docker\/",
|
||||||
|
"slogan": "Grafana is the open source analytics & monitoring solution for every database.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgZ3JhZmFuYToKICAgIGltYWdlOiBncmFmYW5hL2dyYWZhbmEtb3NzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fR1JBRkFOQQogICAgICAtICdHRl9TRVJWRVJfUk9PVF9VUkw9JHtTRVJWSUNFX0ZRRE5fR1JBRkFOQX0nCiAgICAgIC0gJ0dGX1NFUlZFUl9ET01BSU49JHtTRVJWSUNFX0ZRRE5fR1JBRkFOQX0nCiAgICAgIC0gJ0dGX1NFQ1VSSVRZX0FETUlOX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9HUkFGQU5BfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2dyYWZhbmEtZGF0YTovdmFyL2xpYi9ncmFmYW5hJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjMwMDAvYXBpL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||||
|
"tags": [
|
||||||
|
"grafana",
|
||||||
|
"analytics",
|
||||||
|
"monitoring",
|
||||||
|
"dashboard"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"grocy": {
|
||||||
|
"documentation": "https:\/\/github.com\/grocy\/grocy",
|
||||||
|
"slogan": "Grocy is a self-hosted, web-based household management and grocery list application, designed to simplify your household chores and grocery shopping.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgZ3JvY3k6CiAgICBpbWFnZTogJ2xzY3IuaW8vbGludXhzZXJ2ZXIvZ3JvY3k6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0dST0NZCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gVFo9RXVyb3BlL01hZHJpZAogICAgdm9sdW1lczoKICAgICAgLSAnZ3JvY3ktY29uZmlnOi9jb25maWcnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6ODAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK",
|
||||||
|
"tags": [
|
||||||
|
"groceries",
|
||||||
|
"household",
|
||||||
|
"management",
|
||||||
|
"grocery",
|
||||||
|
"shopping"
|
||||||
|
]
|
||||||
|
},
|
||||||
"heimdall": {
|
"heimdall": {
|
||||||
"documentation": "https:\/\/github.com\/linuxserver\/Heimdall",
|
"documentation": "https:\/\/github.com\/linuxserver\/Heimdall",
|
||||||
"slogan": "Heimdall is a self-hosted dashboard for managing and organizing your server applications, providing a centralized and efficient interface.",
|
"slogan": "Heimdall is a self-hosted dashboard for managing and organizing your server applications, providing a centralized and efficient interface.",
|
||||||
@@ -110,8 +179,65 @@
|
|||||||
"api"
|
"api"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"n8n-with-postgresql": {
|
||||||
|
"documentation": "https:\/\/docs.n8n.io\/hosting\/",
|
||||||
|
"slogan": "n8n is an extendable workflow automation tool which enables you to connect anything to everything via its open, fair-code model.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgbjhuOgogICAgaW1hZ2U6IGRvY2tlci5uOG4uaW8vbjhuaW8vbjhuCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fTjhOCiAgICAgIC0gJ044Tl9FRElUT1JfQkFTRV9VUkw9JHtTRVJWSUNFX0ZRRE5fTjhOfScKICAgICAgLSAnTjhOX0hPU1Q9JHtTRVJWSUNFX0ZRRE5fTjhOfScKICAgICAgLSAnR0VORVJJQ19USU1FWk9ORT0iRXVyb3BlL0JlcmxpbiInCiAgICAgIC0gJ1RaPSJFdXJvcGUvQmVybGluIicKICAgICAgLSBEQl9UWVBFPXBvc3RncmVzZGIKICAgICAgLSAnREJfUE9TVEdSRVNEQl9EQVRBQkFTRT0ke1BPU1RHUkVTX0RCOi11bWFtaX0nCiAgICAgIC0gREJfUE9TVEdSRVNEQl9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBEQl9QT1NUR1JFU0RCX1BPUlQ9NTQzMgogICAgICAtIERCX1BPU1RHUkVTREJfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gREJfUE9TVEdSRVNEQl9TQ0hFTUE9cHVibGljCiAgICAgIC0gREJfUE9TVEdSRVNEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFUwogICAgdm9sdW1lczoKICAgICAgLSAnbjhuLWRhdGE6L2hvbWUvbm9kZS8ubjhuJwogICAgZGVwZW5kc19vbjoKICAgICAgLSBwb3N0Z3Jlc3FsCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXVtYW1pfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||||
|
"tags": [
|
||||||
|
"n8n",
|
||||||
|
"workflow",
|
||||||
|
"automation",
|
||||||
|
"open",
|
||||||
|
"source",
|
||||||
|
"low",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"n8n": {
|
||||||
|
"documentation": "https:\/\/docs.n8n.io\/hosting\/",
|
||||||
|
"slogan": "n8n is an extendable workflow automation tool which enables you to connect anything to everything via its open, fair-code model.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgbjhuOgogICAgaW1hZ2U6IGRvY2tlci5uOG4uaW8vbjhuaW8vbjhuCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fTjhOCiAgICAgIC0gJ044Tl9FRElUT1JfQkFTRV9VUkw9JHtTRVJWSUNFX0ZRRE5fTjhOfScKICAgICAgLSAnTjhOX0hPU1Q9JHtTRVJWSUNFX0ZRRE5fTjhOfScKICAgICAgLSAnR0VORVJJQ19USU1FWk9ORT0iRXVyb3BlL0JlcmxpbiInCiAgICAgIC0gJ1RaPSJFdXJvcGUvQmVybGluIicKICAgIHZvbHVtZXM6CiAgICAgIC0gJ244bi1kYXRhOi9ob21lL25vZGUvLm44bicK",
|
||||||
|
"tags": [
|
||||||
|
"n8n",
|
||||||
|
"workflow",
|
||||||
|
"automation",
|
||||||
|
"open",
|
||||||
|
"source",
|
||||||
|
"low",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nocodb": {
|
||||||
|
"documentation": "https:\/\/docs.nocodb.com\/",
|
||||||
|
"slogan": "NocoDB is an open source Airtable alternative. Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart-spreadsheet.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgbm9jb2RiOgogICAgaW1hZ2U6IG5vY29kYi9ub2NvZGIKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9OT0NPREIKICAgIHZvbHVtZXM6CiAgICAgIC0gJ25vY29kYi1kYXRhOi91c3IvYXBwL2RhdGEvJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIHdnZXQKICAgICAgICAtICctcScKICAgICAgICAtICctLXNwaWRlcicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgwODAnCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||||
|
"tags": [
|
||||||
|
"nocodb",
|
||||||
|
"airtable",
|
||||||
|
"mysql",
|
||||||
|
"postgresql",
|
||||||
|
"sqlserver",
|
||||||
|
"sqlite",
|
||||||
|
"mariadb"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"openblocks": {
|
||||||
|
"documentation": "https:\/\/docs.openblocks.dev\/self-hosting",
|
||||||
|
"slogan": "OpenBlocks is a self-hosted, open-source, low-code platform for building internal tools.",
|
||||||
|
"compose": "c2VydmljZXM6CiAgb3BlbmJsb2NrczoKICAgIGltYWdlOiBvcGVuYmxvY2tzZGV2L29wZW5ibG9ja3MtY2UKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9PUEVOQkxPQ0tTCiAgICAgIC0gJ0VOQUJMRV9VU0VSX1NJR05fVVA9JHtFTkFCTEVfVVNFUl9TSUdOX1VQOi10cnVlfScKICAgICAgLSBFTkNSWVBUSU9OX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX0VOQ1JZUFRJT04KICAgICAgLSBFTkNSWVBUSU9OX1NBTFQ9JFNFUlZJQ0VfUEFTU1dPUkRfU0FMVAogICAgdm9sdW1lczoKICAgICAgLSAnb3BlbmJsb2Nrcy1kYXRhOi9vcGVuYmxvY2tzLXN0YWNrcycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDozMDAwL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=",
|
||||||
|
"tags": [
|
||||||
|
"openblocks",
|
||||||
|
"low",
|
||||||
|
"code",
|
||||||
|
"platform",
|
||||||
|
"open",
|
||||||
|
"source",
|
||||||
|
"low",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
"pairdrop": {
|
"pairdrop": {
|
||||||
"documentation": "https:\/\/github.com\/schlagmichdoch\/PairDrop\/blob\/master\/docs\/faq.md",
|
"documentation": "https:\/\/github.com\/schlagmichdoch\/PairDrop",
|
||||||
"slogan": "Pairdrop is a self-hosted file sharing and collaboration platform, offering secure file sharing and collaboration capabilities for efficient teamwork.",
|
"slogan": "Pairdrop is a self-hosted file sharing and collaboration platform, offering secure file sharing and collaboration capabilities for efficient teamwork.",
|
||||||
"compose": "c2VydmljZXM6CiAgcGFpcmRyb3A6CiAgICBpbWFnZTogJ2xzY3IuaW8vbGludXhzZXJ2ZXIvcGFpcmRyb3A6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1BBSVJEUk9QCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gVFo9RXVyb3BlL01hZHJpZAogICAgICAtIERFQlVHX01PREU9ZmFsc2UKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDozMDAwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==",
|
"compose": "c2VydmljZXM6CiAgcGFpcmRyb3A6CiAgICBpbWFnZTogJ2xzY3IuaW8vbGludXhzZXJ2ZXIvcGFpcmRyb3A6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1BBSVJEUk9QCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gVFo9RXVyb3BlL01hZHJpZAogICAgICAtIERFQlVHX01PREU9ZmFsc2UKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDozMDAwJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==",
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -121,8 +247,20 @@
|
|||||||
"teamwork"
|
"teamwork"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"pocketbase": {
|
||||||
|
"documentation": "https:\/\/pocketbase.io\/docs\/",
|
||||||
|
"slogan": "Open Source backend for your next SaaS and Mobile app in 1 file",
|
||||||
|
"compose": "c2VydmljZXM6CiAgcG9ja2V0YmFzZToKICAgIGltYWdlOiAnZ2hjci5pby9jb29sbGFic2lvL3BvY2tldGJhc2U6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1BPQ0tFVEJBU0UKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3BvY2tldGJhc2UtZGF0YTovYXBwL3BiX2RhdGEnCg==",
|
||||||
|
"tags": [
|
||||||
|
"pocketbase",
|
||||||
|
"backend",
|
||||||
|
"saas",
|
||||||
|
"mobile",
|
||||||
|
"api"
|
||||||
|
]
|
||||||
|
},
|
||||||
"snapdrop": {
|
"snapdrop": {
|
||||||
"documentation": "https:\/\/github.com\/RobinLinus\/snapdrop\/blob\/master\/docs\/faq.md",
|
"documentation": "https:\/\/github.com\/RobinLinus\/snapdrop",
|
||||||
"slogan": "A self-hosted file-sharing service for secure and convenient file transfers, whether on a local network or the internet.",
|
"slogan": "A self-hosted file-sharing service for secure and convenient file transfers, whether on a local network or the internet.",
|
||||||
"compose": "c2VydmljZXM6CiAgc25hcGRyb3A6CiAgICBpbWFnZTogJ2xzY3IuaW8vbGludXhzZXJ2ZXIvc25hcGRyb3A6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1NOQVBEUk9QCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gVFo9RXVyb3BlL01hZHJpZAogICAgdm9sdW1lczoKICAgICAgLSAnc25hcGRyb3AtY29uZmlnOi9jb25maWcnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6ODAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK",
|
"compose": "c2VydmljZXM6CiAgc25hcGRyb3A6CiAgICBpbWFnZTogJ2xzY3IuaW8vbGludXhzZXJ2ZXIvc25hcGRyb3A6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1NOQVBEUk9QCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gVFo9RXVyb3BlL01hZHJpZAogICAgdm9sdW1lczoKICAgICAgLSAnc25hcGRyb3AtY29uZmlnOi9jb25maWcnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6ODAnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK",
|
||||||
"tags": [
|
"tags": [
|
||||||
@@ -137,7 +275,7 @@
|
|||||||
"umami": {
|
"umami": {
|
||||||
"documentation": "https:\/\/umami.is\/docs\/getting-started",
|
"documentation": "https:\/\/umami.is\/docs\/getting-started",
|
||||||
"slogan": "Umami is a lightweight, self-hosted web analytics platform designed to provide website owners with insights into visitor behavior without compromising user privacy.",
|
"slogan": "Umami is a lightweight, self-hosted web analytics platform designed to provide website owners with insights into visitor behavior without compromising user privacy.",
|
||||||
"compose": "c2VydmljZXM6CiAgdW1hbWk6CiAgICBpbWFnZTogJ2doY3IuaW8vdW1hbWktc29mdHdhcmUvdW1hbWk6cG9zdGdyZXNxbC1sYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fVU1BTUkKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJFNFUlZJQ0VfVVNFUl9QT1NUR1JFUzokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0Bwb3N0Z3Jlc3FsOjU0MzIvJFBPU1RHUkVTX0RCJwogICAgICAtIERBVEFCQVNFX1RZUEU9cG9zdGdyZXMKICAgICAgLSBBUFBfU0VDUkVUPSRTRVJWSUNFX1BBU1NXT1JEXzY0X1VNQU1JCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXVtYW1pfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMAo=",
|
"compose": "c2VydmljZXM6CiAgdW1hbWk6CiAgICBpbWFnZTogJ2doY3IuaW8vdW1hbWktc29mdHdhcmUvdW1hbWk6cG9zdGdyZXNxbC1sYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fVU1BTUkKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJFNFUlZJQ0VfVVNFUl9QT1NUR1JFUzokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU0Bwb3N0Z3Jlc3FsOjU0MzIvJFBPU1RHUkVTX0RCJwogICAgICAtIERBVEFCQVNFX1RZUEU9cG9zdGdyZXMKICAgICAgLSBBUFBfU0VDUkVUPSRTRVJWSUNFX1BBU1NXT1JEXzY0X1VNQU1JCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXVtYW1pfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK",
|
||||||
"tags": [
|
"tags": [
|
||||||
"analytics",
|
"analytics",
|
||||||
"insights",
|
"insights",
|
||||||
@@ -160,7 +298,7 @@
|
|||||||
},
|
},
|
||||||
"wordpress-with-mariadb": {
|
"wordpress-with-mariadb": {
|
||||||
"documentation": "https:\/\/wordpress.org\/documentation\/",
|
"documentation": "https:\/\/wordpress.org\/documentation\/",
|
||||||
"slogan": "\"WordPress is open source software you can use to create a beautiful website, blog, or app.\"",
|
"slogan": "WordPress with MariaDB. Wordpress is open source software you can use to create a beautiful website, blog, or app.",
|
||||||
"compose": "c2VydmljZXM6CiAgd29yZHByZXNzOgogICAgaW1hZ2U6ICd3b3JkcHJlc3M6bGF0ZXN0JwogICAgdm9sdW1lczoKICAgICAgLSAnd29yZHByZXNzLWZpbGVzOi92YXIvd3d3L2h0bWwnCiAgICBlbnZpcm9ubWVudDoKICAgICAgU0VSVklDRV9GUUROOiBudWxsCiAgICAgIFdPUkRQUkVTU19EQl9IT1NUOiBtYXJpYWRiCiAgICAgIFdPUkRQUkVTU19EQl9VU0VSOiAkU0VSVklDRV9VU0VSX1dPUkRQUkVTUwogICAgICBXT1JEUFJFU1NfREJfUEFTU1dPUkQ6ICRTRVJWSUNFX1BBU1NXT1JEX1dPUkRQUkVTUwogICAgICBXT1JEUFJFU1NfREJfTkFNRTogd29yZHByZXNzCiAgICBkZXBlbmRzX29uOgogICAgICAtIG1hcmlhZGIKICBtYXJpYWRiOgogICAgaW1hZ2U6ICdtYXJpYWRiOjExJwogICAgdm9sdW1lczoKICAgICAgLSAnbWFyaWFkYi1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIE1ZU1FMX1JPT1RfUEFTU1dPUkQ6ICRTRVJWSUNFX1BBU1NXT1JEX1JPT1QKICAgICAgTVlTUUxfREFUQUJBU0U6IHdvcmRwcmVzcwogICAgICBNWVNRTF9VU0VSOiAkU0VSVklDRV9VU0VSX1dPUkRQUkVTUwogICAgICBNWVNRTF9QQVNTV09SRDogJFNFUlZJQ0VfUEFTU1dPUkRfV09SRFBSRVNTCg==",
|
"compose": "c2VydmljZXM6CiAgd29yZHByZXNzOgogICAgaW1hZ2U6ICd3b3JkcHJlc3M6bGF0ZXN0JwogICAgdm9sdW1lczoKICAgICAgLSAnd29yZHByZXNzLWZpbGVzOi92YXIvd3d3L2h0bWwnCiAgICBlbnZpcm9ubWVudDoKICAgICAgU0VSVklDRV9GUUROOiBudWxsCiAgICAgIFdPUkRQUkVTU19EQl9IT1NUOiBtYXJpYWRiCiAgICAgIFdPUkRQUkVTU19EQl9VU0VSOiAkU0VSVklDRV9VU0VSX1dPUkRQUkVTUwogICAgICBXT1JEUFJFU1NfREJfUEFTU1dPUkQ6ICRTRVJWSUNFX1BBU1NXT1JEX1dPUkRQUkVTUwogICAgICBXT1JEUFJFU1NfREJfTkFNRTogd29yZHByZXNzCiAgICBkZXBlbmRzX29uOgogICAgICAtIG1hcmlhZGIKICBtYXJpYWRiOgogICAgaW1hZ2U6ICdtYXJpYWRiOjExJwogICAgdm9sdW1lczoKICAgICAgLSAnbWFyaWFkYi1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIE1ZU1FMX1JPT1RfUEFTU1dPUkQ6ICRTRVJWSUNFX1BBU1NXT1JEX1JPT1QKICAgICAgTVlTUUxfREFUQUJBU0U6IHdvcmRwcmVzcwogICAgICBNWVNRTF9VU0VSOiAkU0VSVklDRV9VU0VSX1dPUkRQUkVTUwogICAgICBNWVNRTF9QQVNTV09SRDogJFNFUlZJQ0VfUEFTU1dPUkRfV09SRFBSRVNTCg==",
|
||||||
"tags": [
|
"tags": [
|
||||||
"cms",
|
"cms",
|
||||||
@@ -172,7 +310,7 @@
|
|||||||
},
|
},
|
||||||
"wordpress-with-mysql": {
|
"wordpress-with-mysql": {
|
||||||
"documentation": "https:\/\/wordpress.org\/documentation\/",
|
"documentation": "https:\/\/wordpress.org\/documentation\/",
|
||||||
"slogan": "\"WordPress is open source software you can use to create a beautiful website, blog, or app.\"",
|
"slogan": "WordPress with MySQL. Wordpress is open source software you can use to create a beautiful website, blog, or app.",
|
||||||
"compose": "c2VydmljZXM6CiAgd29yZHByZXNzOgogICAgaW1hZ2U6ICd3b3JkcHJlc3M6bGF0ZXN0JwogICAgdm9sdW1lczoKICAgICAgLSAnd29yZHByZXNzLWZpbGVzOi92YXIvd3d3L2h0bWwnCiAgICBlbnZpcm9ubWVudDoKICAgICAgU0VSVklDRV9GUUROOiBudWxsCiAgICAgIFdPUkRQUkVTU19EQl9IT1NUOiBteXNxbAogICAgICBXT1JEUFJFU1NfREJfVVNFUjogJFNFUlZJQ0VfVVNFUl9XT1JEUFJFU1MKICAgICAgV09SRFBSRVNTX0RCX1BBU1NXT1JEOiAkU0VSVklDRV9QQVNTV09SRF9XT1JEUFJFU1MKICAgICAgV09SRFBSRVNTX0RCX05BTUU6IHdvcmRwcmVzcwogICAgZGVwZW5kc19vbjoKICAgICAgLSBteXNxbAogIG15c3FsOgogICAgaW1hZ2U6ICdteXNxbDo1LjcnCiAgICB2b2x1bWVzOgogICAgICAtICdteXNxbC1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIE1ZU1FMX1JPT1RfUEFTU1dPUkQ6ICRTRVJWSUNFX1BBU1NXT1JEX1JPT1QKICAgICAgTVlTUUxfREFUQUJBU0U6IHdvcmRwcmVzcwogICAgICBNWVNRTF9VU0VSOiAkU0VSVklDRV9VU0VSX1dPUkRQUkVTUwogICAgICBNWVNRTF9QQVNTV09SRDogJFNFUlZJQ0VfUEFTU1dPUkRfV09SRFBSRVNTCg==",
|
"compose": "c2VydmljZXM6CiAgd29yZHByZXNzOgogICAgaW1hZ2U6ICd3b3JkcHJlc3M6bGF0ZXN0JwogICAgdm9sdW1lczoKICAgICAgLSAnd29yZHByZXNzLWZpbGVzOi92YXIvd3d3L2h0bWwnCiAgICBlbnZpcm9ubWVudDoKICAgICAgU0VSVklDRV9GUUROOiBudWxsCiAgICAgIFdPUkRQUkVTU19EQl9IT1NUOiBteXNxbAogICAgICBXT1JEUFJFU1NfREJfVVNFUjogJFNFUlZJQ0VfVVNFUl9XT1JEUFJFU1MKICAgICAgV09SRFBSRVNTX0RCX1BBU1NXT1JEOiAkU0VSVklDRV9QQVNTV09SRF9XT1JEUFJFU1MKICAgICAgV09SRFBSRVNTX0RCX05BTUU6IHdvcmRwcmVzcwogICAgZGVwZW5kc19vbjoKICAgICAgLSBteXNxbAogIG15c3FsOgogICAgaW1hZ2U6ICdteXNxbDo1LjcnCiAgICB2b2x1bWVzOgogICAgICAtICdteXNxbC1kYXRhOi92YXIvbGliL215c3FsJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIE1ZU1FMX1JPT1RfUEFTU1dPUkQ6ICRTRVJWSUNFX1BBU1NXT1JEX1JPT1QKICAgICAgTVlTUUxfREFUQUJBU0U6IHdvcmRwcmVzcwogICAgICBNWVNRTF9VU0VSOiAkU0VSVklDRV9VU0VSX1dPUkRQUkVTUwogICAgICBNWVNRTF9QQVNTV09SRDogJFNFUlZJQ0VfUEFTU1dPUkRfV09SRFBSRVNTCg==",
|
||||||
"tags": [
|
"tags": [
|
||||||
"cms",
|
"cms",
|
||||||
@@ -184,7 +322,7 @@
|
|||||||
},
|
},
|
||||||
"wordpress-without-database": {
|
"wordpress-without-database": {
|
||||||
"documentation": "https:\/\/wordpress.org\/documentation\/",
|
"documentation": "https:\/\/wordpress.org\/documentation\/",
|
||||||
"slogan": "\"WordPress is open source software you can use to create a beautiful website, blog, or app.\"",
|
"slogan": "WordPress with external database. Wordpress is open source software you can use to create a beautiful website, blog, or app.",
|
||||||
"compose": "c2VydmljZXM6CiAgd29yZHByZXNzOgogICAgaW1hZ2U6ICd3b3JkcHJlc3M6bGF0ZXN0JwogICAgdm9sdW1lczoKICAgICAgLSAnd29yZHByZXNzLWZpbGVzOi92YXIvd3d3L2h0bWwnCiAgICBlbnZpcm9ubWVudDoKICAgICAgU0VSVklDRV9GUUROOiBudWxsCg==",
|
"compose": "c2VydmljZXM6CiAgd29yZHByZXNzOgogICAgaW1hZ2U6ICd3b3JkcHJlc3M6bGF0ZXN0JwogICAgdm9sdW1lczoKICAgICAgLSAnd29yZHByZXNzLWZpbGVzOi92YXIvd3d3L2h0bWwnCiAgICBlbnZpcm9ubWVudDoKICAgICAgU0VSVklDRV9GUUROOiBudWxsCg==",
|
||||||
"tags": [
|
"tags": [
|
||||||
"cms",
|
"cms",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"version": "3.12.36"
|
"version": "3.12.36"
|
||||||
},
|
},
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.100"
|
"version": "4.0.0-beta.106"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user