commit
83a3871d43
@ -72,13 +72,13 @@ private function check_resources($schedule)
|
||||
$containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false);
|
||||
}
|
||||
foreach ($containerServers as $server) {
|
||||
$schedule->job(new ContainerStatusJob($server))->everyTwoMinutes()->onOneServer();
|
||||
$schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer();
|
||||
if ($server->isLogDrainEnabled()) {
|
||||
$schedule->job(new CheckLogDrainContainerJob($server))->everyTwoMinutes()->onOneServer();
|
||||
$schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer();
|
||||
}
|
||||
}
|
||||
foreach ($servers as $server) {
|
||||
$schedule->job(new ServerStatusJob($server))->everyTwoMinutes()->onOneServer();
|
||||
$schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer();
|
||||
}
|
||||
}
|
||||
private function instance_auto_update($schedule)
|
||||
|
@ -38,11 +38,12 @@ public function uniqueId(): int
|
||||
public function handle()
|
||||
{
|
||||
if (!$this->server->isServerReady($this->tries)) {
|
||||
throw new \RuntimeException('Server is not ready.');
|
||||
return "Server is not ready yet.";
|
||||
};
|
||||
try {
|
||||
if ($this->server->isFunctional()) {
|
||||
$this->cleanup(notify: false);
|
||||
$this->removeCoolifyYaml();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
send_internal_notification('ServerStatusJob failed with: ' . $e->getMessage());
|
||||
@ -50,6 +51,16 @@ public function handle()
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
private function removeCoolifyYaml()
|
||||
{
|
||||
// This will remote the coolify.yaml file from the server as it is not needed on cloud servers
|
||||
if (isCloud() && $this->server->id !== 0) {
|
||||
$file = $this->server->proxyPath() . "/dynamic/coolify.yaml";
|
||||
return instant_remote_process([
|
||||
"rm -f $file",
|
||||
], $this->server, false);
|
||||
}
|
||||
}
|
||||
public function cleanup(bool $notify = false): void
|
||||
{
|
||||
$this->disk_usage = $this->server->getDiskUsage();
|
||||
|
@ -82,6 +82,7 @@ public function checkLocalhostConnection()
|
||||
$this->server->settings->is_reachable = true;
|
||||
$this->server->settings->is_usable = true;
|
||||
$this->server->settings->save();
|
||||
$this->dispatch('proxyStatusUpdated');
|
||||
} else {
|
||||
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: ' . $error);
|
||||
return;
|
||||
|
@ -10,6 +10,7 @@
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Sleep;
|
||||
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
||||
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
||||
use Illuminate\Support\Str;
|
||||
@ -239,7 +240,7 @@ public function setupDynamicProxyConfiguration()
|
||||
$dynamic_config_path = $this->proxyPath() . "/dynamic";
|
||||
if ($this->proxyType() === 'TRAEFIK_V2') {
|
||||
$file = "$dynamic_config_path/coolify.yaml";
|
||||
if (empty($settings->fqdn)) {
|
||||
if (empty($settings->fqdn) || (isCloud() && $this->id !== 0)) {
|
||||
instant_remote_process([
|
||||
"rm -f $file",
|
||||
], $this);
|
||||
@ -358,7 +359,7 @@ public function setupDynamicProxyConfiguration()
|
||||
}
|
||||
} else if ($this->proxyType() === 'CADDY') {
|
||||
$file = "$dynamic_config_path/coolify.caddy";
|
||||
if (empty($settings->fqdn)) {
|
||||
if (empty($settings->fqdn) || (isCloud() && $this->id !== 0)) {
|
||||
instant_remote_process([
|
||||
"rm -f $file",
|
||||
], $this);
|
||||
@ -467,63 +468,53 @@ public function isServerReady(int $tries = 3)
|
||||
if ($this->skipServer()) {
|
||||
return false;
|
||||
}
|
||||
$serverUptimeCheckNumber = $this->unreachable_count;
|
||||
if ($this->unreachable_count < $tries) {
|
||||
$serverUptimeCheckNumber = $this->unreachable_count + 1;
|
||||
}
|
||||
if ($this->unreachable_count > $tries) {
|
||||
$serverUptimeCheckNumber = $tries;
|
||||
}
|
||||
|
||||
$serverUptimeCheckNumberMax = $tries;
|
||||
|
||||
// ray('server: ' . $this->name);
|
||||
// ray('serverUptimeCheckNumber: ' . $serverUptimeCheckNumber);
|
||||
// ray('serverUptimeCheckNumberMax: ' . $serverUptimeCheckNumberMax);
|
||||
|
||||
['uptime' => $uptime] = $this->validateConnection();
|
||||
if ($uptime) {
|
||||
if ($this->unreachable_notification_sent === true) {
|
||||
$this->update(['unreachable_notification_sent' => false]);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
|
||||
// Reached max number of retries
|
||||
if ($this->unreachable_notification_sent === false) {
|
||||
ray('Server unreachable, sending notification...');
|
||||
$this->team?->notify(new Unreachable($this));
|
||||
$this->update(['unreachable_notification_sent' => true]);
|
||||
$checkIteration = 1;
|
||||
$isServerReady = false;
|
||||
while ($checkIteration < $tries) {
|
||||
['uptime' => $uptime] = $this->validateConnection();
|
||||
if ($uptime) {
|
||||
if ($this->unreachable_notification_sent === true) {
|
||||
$this->update(['unreachable_notification_sent' => false]);
|
||||
}
|
||||
if ($this->settings->is_reachable === true) {
|
||||
$this->settings()->update([
|
||||
'is_reachable' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($this->applications() as $application) {
|
||||
$application->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($this->databases() as $database) {
|
||||
$database->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($this->services()->get() as $service) {
|
||||
$apps = $service->applications()->get();
|
||||
$dbs = $service->databases()->get();
|
||||
foreach ($apps as $app) {
|
||||
$app->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($dbs as $db) {
|
||||
$db->update(['status' => 'exited']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->update([
|
||||
'unreachable_count' => $this->unreachable_count + 1,
|
||||
$this->settings()->update([
|
||||
'is_reachable' => true,
|
||||
]);
|
||||
$isServerReady = true;
|
||||
break;
|
||||
} else {
|
||||
ray('Server is not ready yet.');
|
||||
$checkIteration++;
|
||||
Sleep::for(10)->seconds();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ($isServerReady) {
|
||||
return $isServerReady;
|
||||
}
|
||||
if ($this->unreachable_notification_sent === false) {
|
||||
ray('Server unreachable, sending notification...');
|
||||
$this->team?->notify(new Unreachable($this));
|
||||
$this->update(['unreachable_notification_sent' => true]);
|
||||
}
|
||||
$this->settings()->update([
|
||||
'is_reachable' => false,
|
||||
]);
|
||||
foreach ($this->applications() as $application) {
|
||||
$application->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($this->databases() as $database) {
|
||||
$database->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($this->services()->get() as $service) {
|
||||
$apps = $service->applications()->get();
|
||||
$dbs = $service->databases()->get();
|
||||
foreach ($apps as $app) {
|
||||
$app->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($dbs as $db) {
|
||||
$db->update(['status' => 'exited']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public function getDiskUsage()
|
||||
{
|
||||
@ -771,6 +762,11 @@ public function validateConnection()
|
||||
$server->settings()->update([
|
||||
'is_reachable' => false,
|
||||
]);
|
||||
if (data_get($server, 'unreachable_notification_sent') === false) {
|
||||
ray('Server unreachable, sending notification...');
|
||||
$this->team?->notify(new Unreachable($this));
|
||||
$this->update(['unreachable_notification_sent' => true]);
|
||||
}
|
||||
return ['uptime' => false, 'error' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
|
@ -988,20 +988,18 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
||||
if ($fqdns_exploded->count() > 1) {
|
||||
continue;
|
||||
}
|
||||
if ($resource->server->proxyType() === 'CADDY') {
|
||||
$env = EnvironmentVariable::where([
|
||||
'key' => $key,
|
||||
'service_id' => $resource->id,
|
||||
])->first();
|
||||
if ($env) {
|
||||
$env = EnvironmentVariable::where([
|
||||
'key' => $key,
|
||||
'service_id' => $resource->id,
|
||||
])->first();
|
||||
if ($env) {
|
||||
|
||||
$env_url = Url::fromString($savedService->fqdn);
|
||||
$env_port = $env_url->getPort();
|
||||
if ($env_port !== $predefinedPort) {
|
||||
$env_url = $env_url->withPort($predefinedPort);
|
||||
$savedService->fqdn = $env_url->__toString();
|
||||
$savedService->save();
|
||||
}
|
||||
$env_url = Url::fromString($savedService->fqdn);
|
||||
$env_port = $env_url->getPort();
|
||||
if ($env_port !== $predefinedPort) {
|
||||
$env_url = $env_url->withPort($predefinedPort);
|
||||
$savedService->fqdn = $env_url->__toString();
|
||||
$savedService->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
// The release version of your application
|
||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||
'release' => '4.0.0-beta.272',
|
||||
'release' => '4.0.0-beta.273',
|
||||
// When left empty or `null` the Laravel environment will be used
|
||||
'environment' => config('app.env'),
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.272';
|
||||
return '4.0.0-beta.273';
|
||||
|
12
public/svgs/vikunja.svg
Normal file
12
public/svgs/vikunja.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 256 256" width="256" height="256">
|
||||
<path d="M2268.2 2512.3a953.7 953.7 0 0 1-50 57c-180.5 189.5-426.2 294-691.6 294A953.7 953.7 0 0 1 847.8 2582a952.7 952.7 0 0 1-281.2-678.8 953.8 953.8 0 0 1 281.2-678.9 953.7 953.7 0 0 1 678.8-281.1 953.7 953.7 0 0 1 678.8 281.1 953.7 953.7 0 0 1 281.2 678.9c0 219.2-78.9 437.2-218.4 609" style="fill:#196aff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1823.7 1650.9c35.7 104.2 94.7 136.1 102 297 2.6 56.5-14.7 236-14.7 236s28 72-25.8 152.3c-83.5 124.3-255.4 132.8-345.7 132.8-90.3 0-260.2-8.5-343.7-132.8C1142 2256 1170 2184 1170 2184s-9.5-92.4-16.7-173.8c-1.7-19.1.1-94.7 2.4-113a453 453 0 0 1 25.8-96.2c14.4-39.6 36.8-79.9 54-120.5 51.8-122.8 8.4-274.9 11.1-407.3 2.2-94-20-189.3-28.7-281.2a960.4 960.4 0 0 1 308.7-50.6 958.6 958.6 0 0 1 344.9 63.6c-20.4 115-44.1 224.2-47.8 265.9-10.6 125.9-41.3 259.4 0 380" style="fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36655635" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1162.9 2383.9c1.1-18.8 3-38 8.3-56.2 1.6-5.7 4-19.7 11.4-21.8 9-2.6 25.9 8.3 32.3 13 12.3 9 23.9 18.5 36.2 27.6 8 6 16.5 10.5 24.3 16.5 8.4 6.6 14.7 14.5 21.7 22.2 8.4 9.4 14.8 19 21.3 29.5 5.1 8.2 37.1 13.5 42.2 21 5.6 8.3 1 18.6 1 28.7 0 74.2 4.4 147.6 6.1 220.3 1.8 50 21.4 109.2-53.4 85.8-160.3-50-158.5-271.3-151.4-386.6M1869.1 2279.7c-1.6 1.8-4.2 3.2-6.3 4.8a208 208 0 0 0-25.1 21.5c-9.4 9.6-19.2 19-28.2 28.9-7.9 8.7-17.3 16.6-25 25.6-5.1 6-10 12.3-14.6 18.5-2.3 3.2-3.5 7-5.3 10.4-2.7 5-40 10.1-36.2 15 6.3 8.3 20.3 15.4 23.7 25 17.2 48.6 24.8 244.5 26.8 294.5 5.4 127.8 117.6-6.3 137.2-57.7 57-149.7 23.2-258.8-46.3-386.6" style="fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1716.5 1787.9c-.1 73.8-9.3 103.6-50.4 139.7-25.8 22.6-55.9 31.2-103.8 30-47.9 1.2-82.4-13.4-107.3-39.2-37.5-39-47.4-62-47.5-135.9 0-39.9 43-128.1 55.7-148.5 21.3-36 60.6-48.9 99.1-46.2 38.6-2.7 77.9 10.3 99.1 46.2 12.8 20.4 55.1 107 55 153.9" style="fill:#f1e6d3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1226.6 2316c-9.6 86.2-38.6 240 61.5 331.3 11 10.1 14-24.2 15.8-38 2.6-19 0-73.5.4-92.6.7-36.1 8.3-55 4.7-71.5-9.6-45-17.3-42.2-26.5-69.6-18.3-54.4-53.3-83-55.9-59.5M1851.7 2333c10.3-18.2 37 80.3 45.4 123.2 8 40.3 18 93.8 4 133.9-7.4 21.5-53 84.5-58.4 62.9-2-8.5-3.2-71.1-8.3-101.1-6.4-37.1-18-73.8-18-111.6-.2-84.5 25.3-88 35.3-107.2" style="fill:#f1d7d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1522 1319.7c-2.2-6.5-18.6-11.4-24.8-13.3-14.9-4.9-28.1 6.9-36.4 16.8-11.6 13.7-11.3 35.6-16.2 51.6-2.9 9.7-19.5 11-24.5 2-16.6-29.8-81.1 26.4-66.1 45.2 9.9 12.3-13.8 23.2-23.6 11-29-36.1 49-103.4 93.6-85.2 2-9 4-18 8-26.6 7.4-16.9 23.9-27.8 41-37 23.1-12.4 68.2 9.5 75 30.3 4.9 14.5-21.2 19.7-26 5.2M1727.6 1538.2c2.4-10 2.8-44-16-25.4-7.5 7.5-22.6 3-23.2-7-1.4-23.4-24.9-24-45.1-16.9-16 5.6-24.6-16.6-8.6-22.1 29.7-10.4 62-4.6 74.7 17.8 10.1-4.7 21.5-6 30.7 2.6 16 15 18.4 36.2 13.7 55.7-3.5 14.8-29.7 10.1-26.2-4.7M1775 1049.2c-7-14.3-19.8-13.4-33.6-7.4-10.1 4.4-22.6-2.8-19.6-13 6.2-20.6-19.7-26.6-37.3-19.3-15.4 6.5-28.8-13.8-13.2-20.3 31.6-13.2 71.7-1.6 77.5 26.2 20.4-3.3 39.8 2.4 49.4 22.3 6.7 13.6-16.4 25.4-23.2 11.5M1569.8 2153.3c-3.3-20.2-41.1 3.3-50.5 9.7-8.3 5.5-19 2.1-20-7.3-1.4-12.7-18.5-9-26.3-7.4-14.8 3-27.4 12.2-27.7 26-.4 13.6 8.2 27.7 12.6 40.4 2.9 8-8.7 17-17.2 11.5-15.2-9.7-88.7-18.5-59.4 13.6 9.3 10.2-7.1 24.8-16.6 14.5-13.5-14.8-22.6-48.7 6.6-56 15.5-3.7 37.8-3.5 56.8.8-8-25.5-9.6-48.8 23.2-65.1 22.1-11.1 52.5-11 65.4 6 27.2-14.5 69.7-28.7 75.6 7.8 2.1 13-20.4 18.5-22.5 5.5" style="fill:#faeee0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1443 1685.6c39.4-3.4 78.8-12.3 118.5-10.9 25.4 1 51.7 4.5 76.8 8.2 18.2 2.7 40.5 6 52.7 19.4 1-45-92.6-59.1-128.9-60-42.1-1-89.5 17.2-119 43.3" style="fill:#494949;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1549.4 1779.5a353.5 353.5 0 0 1-2.7-87.3c.7-7.6-1.3-25.7 8.8-29.5 8.2-3 18.3 2.7 19.7 10.1 2.2 12.5-3 28.2-3.5 41-.5 14.9 0 29.8 1.6 44.7 1 8.8 5.9 20.7-4.2 27-7.4 4.5-18.3 2.8-19.7-6" style="fill:#494949;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1626 1849.7c-23.7-1-45.7-14.2-63.4-27-16.1 10.7-40.5 20.5-60.7 14.8-12-3.4-1.1-7.1 4-10.3 9.2-6.2 16.8-14.2 23.7-22.4 10.3-12.6 19.6-25.8 30.7-38 7.6 5.6 15 11.1 21.6 17.6 3.1 3 28.5 37 32.4 42.7 2.4 3.6 5 7.4 7.8 10.8 2.9 3.5 11 9 3.9 11.8" style="fill:#494949;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
<path d="M1326.5 2010c11.7 30.3 24.3 68.4 56.3 62.4 24.2-5.2 56.7-86.2 36-78.2-11.3 4.4-20.3 41.1-41.4 46-13.4 3-32-43.6-50-48.4-8.7-2.3-4.3 10.4-.9 18.2M1670.6 2010c11.7 30.3 24.2 68.4 56.3 62.4 24.2-5.2 56.7-86.2 35.9-78.2-11.3 4.4-20.2 41.1-41.3 46-13.5 3-32-43.6-50-48.4-8.7-2.3-4.4 10.4-1 18.2" style="fill:#2c3844;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:.36633128" transform="matrix(.13333 0 0 -.13333 -75.5 381.8)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 5.4 KiB |
@ -2,13 +2,7 @@
|
||||
<livewire:server.proxy.modal :server="$server" />
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>Server</h1>
|
||||
@if (
|
||||
$server->proxyType() !== 'NONE' &&
|
||||
$server->isFunctional() &&
|
||||
!$server->isSwarmWorker() &&
|
||||
!$server->settings->is_build_server)
|
||||
<livewire:server.proxy.status :server="$server" />
|
||||
@endif
|
||||
<livewire:server.proxy.status :server="$server" />
|
||||
</div>
|
||||
<div class="subtitle">{{ data_get($server, 'name') }}.</div>
|
||||
<nav class="navbar-main">
|
||||
@ -52,12 +46,6 @@
|
||||
@endif
|
||||
|
||||
<div class="flex-1"></div>
|
||||
@if (
|
||||
$server->proxyType() !== 'NONE' &&
|
||||
$server->isFunctional() &&
|
||||
!$server->isSwarmWorker() &&
|
||||
!$server->settings->is_build_server)
|
||||
<livewire:server.proxy.deploy :server="$server" />
|
||||
@endif
|
||||
<livewire:server.proxy.deploy :server="$server" />
|
||||
</nav>
|
||||
</div>
|
||||
|
@ -45,9 +45,9 @@ class="button">+
|
||||
class="items-center justify-center box">+ Add New Resource</a>
|
||||
@else
|
||||
<div x-data="searchComponent()">
|
||||
<x-forms.input autofocus placeholder="Search for name, fqdn..." x-model="search" />
|
||||
<x-forms.input autofocus placeholder="Search for name, fqdn..." x-model="search" id="null" />
|
||||
<div class="grid grid-cols-1 gap-4 pt-4 lg:grid-cols-2 xl:grid-cols-3">
|
||||
<template x-for="item in filteredApplications" :key="item.id">
|
||||
<template x-for="item in filteredApplications" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -79,7 +79,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredPostgresqls" :key="item.id">
|
||||
<template x-for="item in filteredPostgresqls" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -110,7 +110,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredRedis" :key="item.id">
|
||||
<template x-for="item in filteredRedis" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -141,7 +141,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredMongodbs" :key="item.id">
|
||||
<template x-for="item in filteredMongodbs" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -172,7 +172,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredMysqls" :key="item.id">
|
||||
<template x-for="item in filteredMysqls" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -203,7 +203,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredMariadbs" :key="item.id">
|
||||
<template x-for="item in filteredMariadbs" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -234,7 +234,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredKeydbs" :key="item.id">
|
||||
<template x-for="item in filteredKeydbs" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -265,7 +265,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredDragonflies" :key="item.id">
|
||||
<template x-for="item in filteredDragonflies" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -296,7 +296,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredClickhouses" :key="item.id">
|
||||
<template x-for="item in filteredClickhouses" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -327,7 +327,7 @@ class="items-center justify-center box">+ Add New Resource</a>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
<template x-for="item in filteredServices" :key="item.id">
|
||||
<template x-for="item in filteredServices" :key="item.uuid">
|
||||
<span>
|
||||
<a class="h-24 box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col w-full">
|
||||
@ -395,7 +395,7 @@ function searchComponent() {
|
||||
}
|
||||
this.applications = Object.values(this.applications);
|
||||
return this.applications.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.fqdn?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
@ -407,7 +407,7 @@ function searchComponent() {
|
||||
}
|
||||
this.postgresqls = Object.values(this.postgresqls);
|
||||
return this.postgresqls.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
@ -418,7 +418,7 @@ function searchComponent() {
|
||||
}
|
||||
this.redis = Object.values(this.redis);
|
||||
return this.redis.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
@ -429,7 +429,7 @@ function searchComponent() {
|
||||
}
|
||||
this.mongodbs = Object.values(this.mongodbs);
|
||||
return this.mongodbs.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
@ -440,7 +440,7 @@ function searchComponent() {
|
||||
}
|
||||
this.mysqls = Object.values(this.mysqls);
|
||||
return this.mysqls.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
@ -451,7 +451,7 @@ function searchComponent() {
|
||||
}
|
||||
this.mariadbs = Object.values(this.mariadbs);
|
||||
return this.mariadbs.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
@ -462,7 +462,7 @@ function searchComponent() {
|
||||
}
|
||||
this.keydbs = Object.values(this.keydbs);
|
||||
return this.keydbs.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
@ -473,7 +473,7 @@ function searchComponent() {
|
||||
}
|
||||
this.dragonflies = Object.values(this.dragonflies);
|
||||
return this.dragonflies.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
@ -484,7 +484,7 @@ function searchComponent() {
|
||||
}
|
||||
this.clickhouses = Object.values(this.clickhouses);
|
||||
return this.clickhouses.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
@ -495,7 +495,7 @@ function searchComponent() {
|
||||
}
|
||||
this.services = Object.values(this.services);
|
||||
return this.services.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
return item.name?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.tags?.some(tag => tag.name.toLowerCase().includes(this.search.toLowerCase()));
|
||||
}).sort(sortFn);
|
||||
|
@ -5,7 +5,7 @@
|
||||
<form wire:submit='submit'>
|
||||
<div class="flex items-center gap-2">
|
||||
<h2>Configuration</h2>
|
||||
@if ($server->proxy->status === 'exited')
|
||||
@if ($server->proxy->status === 'exited' || $server->proxy->status === 'removing')
|
||||
<x-forms.button wire:click.prevent="change_proxy">Switch Proxy</x-forms.button>
|
||||
@else
|
||||
<x-forms.button disabled wire:click.prevent="change_proxy">Switch Proxy</x-forms.button>
|
||||
|
@ -1,5 +1,9 @@
|
||||
<div>
|
||||
@if ($server->isFunctional() && $server->proxyType() !== 'NONE')
|
||||
@if (
|
||||
$server->proxyType() !== 'NONE' &&
|
||||
$server->isFunctional() &&
|
||||
!$server->isSwarmWorker() &&
|
||||
!$server->settings->is_build_server)
|
||||
<x-slide-over closeWithX fullScreen @startproxy.window="slideOverOpen = true">
|
||||
<x-slot:title>Proxy Status</x-slot:title>
|
||||
<x-slot:content>
|
||||
|
@ -1,5 +1,9 @@
|
||||
<div x-init="$wire.checkProxy()">
|
||||
@if ($server->isFunctional())
|
||||
@if (
|
||||
$server->proxyType() !== 'NONE' &&
|
||||
$server->isFunctional() &&
|
||||
!$server->isSwarmWorker() &&
|
||||
!$server->settings->is_build_server)
|
||||
<div class="flex gap-2">
|
||||
@if (data_get($server, 'proxy.status') === 'running')
|
||||
<x-status.running status="Proxy Running" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
@if (auth()->user()->isAdminFromSession())
|
||||
<div>
|
||||
<div class="flex gap-2">
|
||||
<h1>Choose a Plan</h1>
|
||||
<h1>Subscriptions</h1>
|
||||
@if (subscriptionProvider() === 'stripe' && $alreadySubscribed)
|
||||
<x-forms.button wire:click='stripeCustomerPortal'>Manage My Subscription</x-forms.button>
|
||||
@endif
|
||||
|
@ -1,31 +1,24 @@
|
||||
<div x-data="{ selected: 'monthly' }" class="w-full pb-20">
|
||||
<div class="max-w-3xl px-6 mx-auto lg:px-8">
|
||||
<div class="px-6 mx-auto lg:px-8">
|
||||
<div class="flex justify-center">
|
||||
<fieldset
|
||||
class="grid grid-cols-2 p-1 text-xs font-semibold leading-5 text-center rounded dark:text-white gap-x-1 bg-white/5">
|
||||
class="grid grid-cols-2 p-1 text-xs font-semibold leading-5 text-center rounded dark:text-white gap-x-1 dark:bg-white/5 bg-black/5">
|
||||
<legend class="sr-only">Payment frequency</legend>
|
||||
<label class="cursor-pointer rounded px-2.5 py-1"
|
||||
:class="selected === 'monthly' ? 'bg-coollabs-100 text-white' : ''">
|
||||
:class="selected === 'monthly' ? 'dark:bg-coollabs-100 bg-warning dark:text-white' : ''">
|
||||
<input type="radio" x-on:click="selected = 'monthly'" name="frequency" value="monthly"
|
||||
class="sr-only">
|
||||
<span>Monthly</span>
|
||||
</label>
|
||||
<label class="cursor-pointer rounded px-2.5 py-1"
|
||||
:class="selected === 'yearly' ? 'bg-coollabs-100 text-white' : ''">
|
||||
:class="selected === 'yearly' ? 'dark:bg-coollabs-100 bg-warning dark:text-white' : ''">
|
||||
<input type="radio" x-on:click="selected = 'yearly'" name="frequency" value="annually"
|
||||
class="sr-only">
|
||||
<span>Annually</span>
|
||||
<span>Annually <span class="text-xs dark:text-warning text-coollabs">(save ~20%)</span
|
||||
></span>
|
||||
</label>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div x-show="selected === 'monthly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
|
||||
<div>Save <span class="font-bold text-black dark:text-warning">10%</span> annually with the yearly plans.
|
||||
</div>
|
||||
</div>
|
||||
<div x-show="selected === 'yearly'" class="flex justify-center h-10 mt-3 text-sm leading-6 ">
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-root mt-12">
|
||||
{{-- <div class="pb-10 text-xl text-center">For the detailed list of features, please visit our landing page: <a
|
||||
class="font-bold underline dark:text-white" href="https://coolify.io">coolify.io</a></div> --}}
|
||||
@ -33,34 +26,60 @@ class="font-bold underline dark:text-white" href="https://coolify.io">coolify.io
|
||||
class="grid max-w-sm grid-cols-1 -mt-16 divide-y divide-neutral-200 dark:divide-coolgray-500 isolate gap-y-16 sm:mx-auto lg:-mx-8 lg:mt-0 lg:max-w-none lg:grid-cols-1 lg:divide-x lg:divide-y-0 xl:-mx-4">
|
||||
<div class="pt-16 lg:px-8 lg:pt-0 xl:px-14">
|
||||
<h3 id="tier-dynamic" class="text-4xl font-semibold leading-7 dark:text-white">Pay-as-you-go</h3>
|
||||
<p class="mt-4 text-sm leading-6 dark:text-neutral-400">
|
||||
Dynamic pricing based on the number of servers you connect.
|
||||
</p>
|
||||
<p class="flex items-baseline mt-6 gap-x-1">
|
||||
<span x-show="selected === 'monthly'" x-cloak>
|
||||
<span class="text-4xl font-bold tracking-tight dark:text-white">$5</span>
|
||||
<span class="text-sm font-semibold leading-6 "> for 2 servers</span>
|
||||
<span class="text-sm font-semibold leading-6 "> base price</span>
|
||||
</span>
|
||||
|
||||
<span x-show="selected === 'yearly'" x-cloak>
|
||||
<span class="text-4xl font-bold tracking-tight dark:text-white">$4</span>
|
||||
<span class="text-sm font-semibold leading-6 "> for 2 servers</span>
|
||||
<span class="text-sm font-semibold leading-6 "> base price</span>
|
||||
</span>
|
||||
</p>
|
||||
<p class="flex items-baseline mb-4 gap-x-1">
|
||||
<span x-show="selected === 'monthly'" x-cloak>
|
||||
<span class="text-sm font-semibold tracking-tight dark:text-white">$3</span>
|
||||
<span class="text-sm font-semibold leading-6 "> per server from 3+ servers</span>
|
||||
<span class="text-base font-semibold tracking-tight dark:text-white">$3</span>
|
||||
<span class="text-sm font-semibold leading-6 "> per additional servers <span class="font-normal dark:text-white">billed monthly (+VAT)</span></span>
|
||||
</span>
|
||||
|
||||
<span x-show="selected === 'yearly'" x-cloak>
|
||||
<span class="text-sm font-semibold tracking-tight dark:text-white">$2.7</span>
|
||||
<span class="text-sm font-semibold leading-6 "> per server from 3+ servers</span>
|
||||
<span class="text-base font-semibold tracking-tight dark:text-white">$2.7</span>
|
||||
<span class="text-sm font-semibold leading-6 "> per additional servers <span class="font-normal dark:text-white">billed annually (+VAT)</span></span>
|
||||
</span>
|
||||
</p>
|
||||
<span x-show="selected === 'monthly'" x-cloak>
|
||||
<span class="dark:text-white p">billed monthly (+VAT)</span>
|
||||
</span>
|
||||
<span x-show="selected === 'yearly'" x-cloak>
|
||||
<span class="dark:text-white">billed annually (+VAT)</span>
|
||||
</span>
|
||||
<div class="flex items-center pt-6">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="flex-none w-8 h-8 mr-3 text-warning"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 256 256"
|
||||
><path
|
||||
d="M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z"
|
||||
></path></svg
|
||||
>
|
||||
|
||||
<div class="flex flex-col text-sm text-white">
|
||||
<div>
|
||||
You need to bring your own servers from any cloud provider (such as <a
|
||||
class="underline"
|
||||
href="https://coolify.io/hetzner"
|
||||
target="_blank">Hetzner</a
|
||||
>, DigitalOcean, AWS, etc.)
|
||||
</div>
|
||||
<div>
|
||||
(You can connect your RPi, old laptop, or any other device that runs
|
||||
the <a
|
||||
class="underline"
|
||||
href="https://coolify.io/docs/installation#supported-operating-systems"
|
||||
target="_blank">supported operating systems</a
|
||||
>.)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<x-forms.button x-show="selected === 'monthly'" x-cloak aria-describedby="tier-basic"
|
||||
class="w-full h-10 buyme" wire:click="subscribeStripe('dynamic-monthly')">
|
||||
Subscribe
|
||||
@ -69,47 +88,122 @@ class="w-full h-10 buyme" wire:click="subscribeStripe('dynamic-monthly')">
|
||||
class="w-full h-10 buyme" wire:click="subscribeStripe('dynamic-yearly')">
|
||||
Subscribe
|
||||
</x-forms.button>
|
||||
<ul role="list" class="pt-6 space-y-3 text-sm leading-6">
|
||||
<ul role="list" class="mt-8 space-y-3 text-sm leading-6 dark:text-neutral-400">
|
||||
<li class="flex">
|
||||
<svg class="flex-none w-5 h-6 mr-3 dark:text-warning" viewBox="0 0 20 20"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.775 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
Connect <span class="px-1 font-bold dark:text-white">unlimited</span> servers
|
||||
<svg
|
||||
class="flex-none w-5 h-6 mr-3 text-warning"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Connect
|
||||
<span class="px-1 font-bold dark:text-white">unlimited</span> servers
|
||||
</li>
|
||||
<li class="flex">
|
||||
<svg
|
||||
class="flex-none w-5 h-6 mr-3 text-warning"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Deploy
|
||||
<span class="px-1 font-bold dark:text-white">unlimited</span> applications per server
|
||||
</li>
|
||||
<li class="flex gap-x-3">
|
||||
<svg class="flex-none w-5 h-6 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
Free Email Notifications
|
||||
<svg
|
||||
class="flex-none w-5 h-6 text-warning"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Free email notifications
|
||||
</li>
|
||||
<li class="flex gap-x-3">
|
||||
<svg class="flex-none w-5 h-6 dark:text-warning" viewBox="0 0 20 20" fill="currentColor"
|
||||
aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
Support by Email
|
||||
<svg
|
||||
class="flex-none w-5 h-6 text-warning"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Support by email
|
||||
</li>
|
||||
<li class="flex font-bold dark:text-white gap-x-3">
|
||||
<svg width="512" height="512" class="flex-none w-5 h-6 text-green-600"
|
||||
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="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3-5a9 9 0 0 0 6-8a3 3 0 0 0-3-3a9 9 0 0 0-8 6a6 6 0 0 0-5 3" />
|
||||
<path d="M7 14a6 6 0 0 0-3 6a6 6 0 0 0 6-3m4-8a1 1 0 1 0 2 0a1 1 0 1 0-2 0" />
|
||||
</g>
|
||||
</svg>
|
||||
+ All upcoming features
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
class="flex-none w-5 h-6 text-green-500"
|
||||
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="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3-5a9 9 0 0 0 6-8a3 3 0 0 0-3-3a9 9 0 0 0-8 6a6 6 0 0 0-5 3"
|
||||
/>
|
||||
<path
|
||||
d="M7 14a6 6 0 0 0-3 6a6 6 0 0 0 6-3m4-8a1 1 0 1 0 2 0a1 1 0 1 0-2 0"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
+ All Upcoming Features
|
||||
</li>
|
||||
</ul>
|
||||
<li class="flex dark:text-white gap-x-3">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="flex-none w-5 h-6 text-green-500"
|
||||
viewBox="0 0 256 256"
|
||||
><rect width="256" height="256" fill="none" /><polyline
|
||||
points="32 136 72 136 88 112 120 160 136 136 160 136"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="16"
|
||||
/><path
|
||||
d="M24,104c0-.67,0-1.33,0-2A54,54,0,0,1,78,48c22.59,0,41.94,12.31,50,32,8.06-19.69,27.41-32,50-32a54,54,0,0,1,54,54c0,66-104,122-104,122s-42-22.6-72.58-56"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="16"
|
||||
/></svg
|
||||
>
|
||||
|
||||
Do you require official support for your self-hosted instance?<a
|
||||
class="underline"
|
||||
href="https://coolify.io/docs/contact">Contact Us</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="grid gap-2 lg:grid-cols-2">
|
||||
@forelse ($privateKeys as $key)
|
||||
<a class="box"
|
||||
<a class="box group"
|
||||
href="{{ route('security.private-key.show', ['private_key_uuid' => data_get($key, 'uuid')]) }}">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="box-title">
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
services:
|
||||
formbricks:
|
||||
image: formbricks/formbricks:latest
|
||||
image: ghcr.io/formbricks/formbricks:latest
|
||||
environment:
|
||||
- SERVICE_FQDN_FORMBRICKS_3000
|
||||
- WEBAPP_URL=$SERVICE_FQDN_FORMBRICKS
|
||||
|
@ -13,7 +13,7 @@ services:
|
||||
ports:
|
||||
- 22222:22
|
||||
volumes:
|
||||
- gitea-data:/var/lib/gitea
|
||||
- gitea-data:/data
|
||||
- gitea-timezone:/etc/timezone:ro
|
||||
- gitea-localtime:/etc/localtime:ro
|
||||
healthcheck:
|
||||
|
@ -169,11 +169,12 @@ services:
|
||||
- anon
|
||||
|
||||
## Secure Realtime routes
|
||||
- name: realtime-v1
|
||||
- name: realtime-v1-ws
|
||||
_comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*'
|
||||
url: http://realtime-dev.supabase-realtime:4000/socket/
|
||||
url: http://realtime-dev:4000/socket
|
||||
protocol: ws
|
||||
routes:
|
||||
- name: realtime-v1-all
|
||||
- name: realtime-v1-ws
|
||||
strip_path: true
|
||||
paths:
|
||||
- /realtime/v1/
|
||||
@ -188,6 +189,26 @@ services:
|
||||
allow:
|
||||
- admin
|
||||
- anon
|
||||
- name: realtime-v1-rest
|
||||
_comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*'
|
||||
url: http://realtime-dev:4000/api
|
||||
protocol: http
|
||||
routes:
|
||||
- name: realtime-v1-rest
|
||||
strip_path: true
|
||||
paths:
|
||||
- /realtime/v1/api
|
||||
plugins:
|
||||
- name: cors
|
||||
- name: key-auth
|
||||
config:
|
||||
hide_credentials: false
|
||||
- name: acl
|
||||
config:
|
||||
hide_groups_header: true
|
||||
allow:
|
||||
- admin
|
||||
- anon
|
||||
|
||||
## Storage routes: the storage server manages its own auth
|
||||
- name: storage-v1
|
||||
@ -257,7 +278,7 @@ services:
|
||||
config:
|
||||
hide_credentials: true
|
||||
supabase-studio:
|
||||
image: supabase/studio:20240415-304bec8
|
||||
image: supabase/studio:20240422-5cf8f30
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
@ -293,7 +314,7 @@ services:
|
||||
# Uncomment to use Big Query backend for analytics
|
||||
# NEXT_ANALYTICS_BACKEND_PROVIDER=bigquery
|
||||
supabase-db:
|
||||
image: supabase/postgres:15.1.0.147
|
||||
image: supabase/postgres:15.1.1.41
|
||||
healthcheck:
|
||||
test: pg_isready -U postgres -h localhost
|
||||
interval: 5s
|
||||
@ -572,6 +593,9 @@ services:
|
||||
|
||||
create schema if not exists _analytics;
|
||||
alter schema _analytics owner to :pguser;
|
||||
# Use named volume to persist pgsodium decryption key between restarts
|
||||
- supabase-db-config:/etc/postgresql-custom
|
||||
|
||||
supabase-analytics:
|
||||
image: supabase/logflare:1.4.0
|
||||
healthcheck:
|
||||
@ -600,6 +624,7 @@ services:
|
||||
- LOGFLARE_SINGLE_TENANT=true
|
||||
- LOGFLARE_SINGLE_TENANT_MODE=true
|
||||
- LOGFLARE_SUPABASE_MODE=true
|
||||
- LOGFLARE_MIN_CLUSTER_SIZE=1
|
||||
|
||||
# Comment variables to use Big Query backend for analytics
|
||||
- POSTGRES_BACKEND_URL=postgresql://supabase_admin:${SERVICE_PASSWORD_POSTGRES}@${POSTGRES_HOST:-supabase-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-postgres}
|
||||
@ -665,7 +690,7 @@ services:
|
||||
kong: 'starts_with(string!(.appname), "supabase-kong")'
|
||||
auth: 'starts_with(string!(.appname), "supabase-auth")'
|
||||
rest: 'starts_with(string!(.appname), "supabase-rest")'
|
||||
realtime: 'starts_with(string!(.appname), "realtime-dev.supabase-realtime")'
|
||||
realtime: 'starts_with(string!(.appname), "realtime-dev")'
|
||||
storage: 'starts_with(string!(.appname), "supabase-storage")'
|
||||
functions: 'starts_with(string!(.appname), "supabase-functions")'
|
||||
db: 'starts_with(string!(.appname), "supabase-db")'
|
||||
@ -797,7 +822,7 @@ services:
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 10
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=gotrue.logs.prod&api_key=${LOGFLARE_API_KEY}'
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=gotrue.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||
logflare_realtime:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@ -807,7 +832,7 @@ services:
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 10
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=realtime.logs.prod&api_key=${LOGFLARE_API_KEY}'
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=realtime.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||
logflare_rest:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@ -817,7 +842,7 @@ services:
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 10
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=postgREST.logs.prod&api_key=${LOGFLARE_API_KEY}'
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=postgREST.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||
logflare_db:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@ -830,7 +855,7 @@ services:
|
||||
# We must route the sink through kong because ingesting logs before logflare is fully initialised will
|
||||
# lead to broken queries from studio. This works by the assumption that containers are started in the
|
||||
# following order: vector > db > logflare > kong
|
||||
uri: 'http://supabase-kong:8000/analytics/v1/api/logs?source_name=postgres.logs&api_key=${LOGFLARE_API_KEY}'
|
||||
uri: 'http://supabase-kong:8000/analytics/v1/api/logs?source_name=postgres.logs&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||
logflare_functions:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@ -840,7 +865,7 @@ services:
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 10
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=deno-relay-logs&api_key=${LOGFLARE_API_KEY}'
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=deno-relay-logs&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||
logflare_storage:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@ -850,7 +875,7 @@ services:
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 10
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=storage.logs.prod.2&api_key=${LOGFLARE_API_KEY}'
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=storage.logs.prod.2&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||
logflare_kong:
|
||||
type: 'http'
|
||||
inputs:
|
||||
@ -861,7 +886,7 @@ services:
|
||||
method: 'post'
|
||||
request:
|
||||
retry_max_duration_secs: 10
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=cloudflare.logs.prod&api_key=${LOGFLARE_API_KEY}'
|
||||
uri: 'http://supabase-analytics:4000/api/logs?source_name=cloudflare.logs.prod&api_key=${LOGFLARE_API_KEY?LOGFLARE_API_KEY is required}'
|
||||
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
environment:
|
||||
@ -887,7 +912,7 @@ services:
|
||||
- PGRST_APP_SETTINGS_JWT_EXP=${JWT_EXPIRY:-3600}
|
||||
command: "postgrest"
|
||||
supabase-auth:
|
||||
image: supabase/gotrue:v2.145.0
|
||||
image: supabase/gotrue:v2.149.0
|
||||
depends_on:
|
||||
supabase-db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
@ -926,6 +951,7 @@ services:
|
||||
- GOTRUE_JWT_SECRET=${SERVICE_PASSWORD_JWT}
|
||||
|
||||
- GOTRUE_EXTERNAL_EMAIL_ENABLED=${ENABLE_EMAIL_SIGNUP:-true}
|
||||
- GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED=${ENABLE_ANONYMOUS_USERS:-false}
|
||||
- GOTRUE_MAILER_AUTOCONFIRM=${ENABLE_EMAIL_AUTOCONFIRM:-false}
|
||||
# GOTRUE_MAILER_SECURE_EMAIL_CHANGE_ENABLED=true
|
||||
# GOTRUE_SMTP_MAX_FREQUENCY=1s
|
||||
@ -953,9 +979,20 @@ services:
|
||||
|
||||
- GOTRUE_EXTERNAL_PHONE_ENABLED=${ENABLE_PHONE_SIGNUP:-true}
|
||||
- GOTRUE_SMS_AUTOCONFIRM=${ENABLE_PHONE_AUTOCONFIRM:-true}
|
||||
# Uncomment to enable custom access token hook. You'll need to create a public.custom_access_token_hook function and grant necessary permissions.
|
||||
# See: https://supabase.com/docs/guides/auth/auth-hooks#hook-custom-access-token for details
|
||||
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED="true"
|
||||
# GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI="pg-functions://postgres/public/custom_access_token_hook"
|
||||
|
||||
# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED="true"
|
||||
# GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI="pg-functions://postgres/public/mfa_verification_attempt"
|
||||
|
||||
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED="true"
|
||||
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI="pg-functions://postgres/public/password_verification_attempt"
|
||||
|
||||
realtime-dev:
|
||||
# This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
|
||||
image: supabase/realtime:v2.28.23
|
||||
image: supabase/realtime:v2.28.32
|
||||
container_name: realtime-dev.supabase-realtime
|
||||
depends_on:
|
||||
supabase-db:
|
||||
@ -1121,7 +1158,7 @@ services:
|
||||
- PG_META_DB_PASSWORD=${SERVICE_PASSWORD_POSTGRES}
|
||||
|
||||
supabase-edge-functions:
|
||||
image: supabase/edge-runtime:v1.43.2
|
||||
image: supabase/edge-runtime:v1.45.2
|
||||
depends_on:
|
||||
supabase-analytics:
|
||||
condition: service_healthy
|
||||
|
21
templates/compose/vikunja.yaml
Normal file
21
templates/compose/vikunja.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
# documentation: https://vikunja.io
|
||||
# slogan: The open-source, self-hostable to-do app. Organize everything, on all platforms.
|
||||
# tags: productivity,todo
|
||||
# logo: svgs/vikunja.svg
|
||||
# port: 3456
|
||||
|
||||
services:
|
||||
vikunja:
|
||||
image: vikunja/vikunja
|
||||
environment:
|
||||
- SERVICE_FQDN_VIKUNJA
|
||||
- VIKUNJA_SERVICE_PUBLICURL=$SERVICE_FQDN_VIKUNJA
|
||||
- VIKUNJA_SERVICE_JWTSECRET=$SERVICE_PASSWORD_JWTSECRET
|
||||
- VIKUNJA_SERVICE_ENABLEREGISTRATION=true
|
||||
volumes:
|
||||
- vikunja-data:/app/vikunja/
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "http://localhost:3456"]
|
||||
interval: 5s
|
||||
timeout: 20s
|
||||
retries: 10
|
File diff suppressed because one or more lines are too long
@ -1,7 +1,7 @@
|
||||
{
|
||||
"coolify": {
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.272"
|
||||
"version": "4.0.0-beta.273"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user