diff --git a/.github/workflows/coolify-production-build.yml b/.github/workflows/coolify-production-build.yml index 79dfc3fc0..5271143ec 100644 --- a/.github/workflows/coolify-production-build.yml +++ b/.github/workflows/coolify-production-build.yml @@ -11,7 +11,7 @@ on: - docker/coolify-helper/Dockerfile - docker/coolify-realtime/Dockerfile - docker/testing-host/Dockerfile - - templates/* + - templates/** env: GITHUB_REGISTRY: ghcr.io diff --git a/.github/workflows/coolify-staging-build.yml b/.github/workflows/coolify-staging-build.yml index 1aafc2f0b..2c57a36a3 100644 --- a/.github/workflows/coolify-staging-build.yml +++ b/.github/workflows/coolify-staging-build.yml @@ -11,7 +11,7 @@ on: - docker/coolify-helper/Dockerfile - docker/coolify-realtime/Dockerfile - docker/testing-host/Dockerfile - - templates/* + - templates/** env: GITHUB_REGISTRY: ghcr.io diff --git a/app/Actions/Application/IsHorizonQueueEmpty.php b/app/Actions/Application/IsHorizonQueueEmpty.php new file mode 100644 index 000000000..17966b8a0 --- /dev/null +++ b/app/Actions/Application/IsHorizonQueueEmpty.php @@ -0,0 +1,37 @@ +getRecent(); + if ($recent) { + $running = $recent->filter(function ($job) use ($hostname) { + $payload = json_decode($job->payload); + $tags = data_get($payload, 'tags'); + + return $job->status != 'completed' && + $job->status != 'failed' && + isset($tags) && + is_array($tags) && + in_array('server:'.$hostname, $tags); + }); + if ($running->count() > 0) { + echo 'false'; + + return false; + } + } + echo 'true'; + + return true; + } +} diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php index ba6c23ffc..cbcb20368 100644 --- a/app/Actions/Server/InstallDocker.php +++ b/app/Actions/Server/InstallDocker.php @@ -12,7 +12,7 @@ class InstallDocker public function handle(Server $server) { - $dockerVersion = config('constants.docker_install_version'); + $dockerVersion = config('constants.docker.minimum_required_version'); $supported_os_type = $server->validateOS(); if (! $supported_os_type) { throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: documentation.'); diff --git a/app/Console/Commands/CloudCheckSubscription.php b/app/Console/Commands/CloudCheckSubscription.php new file mode 100644 index 000000000..6e237e84b --- /dev/null +++ b/app/Console/Commands/CloudCheckSubscription.php @@ -0,0 +1,49 @@ +get(); + foreach ($activeSubscribers as $team) { + $stripeSubscriptionId = $team->subscription->stripe_subscription_id; + $stripeInvoicePaid = $team->subscription->stripe_invoice_paid; + $stripeCustomerId = $team->subscription->stripe_customer_id; + if (! $stripeSubscriptionId) { + echo "Team {$team->id} has no subscription, but invoice status is: {$stripeInvoicePaid}\n"; + echo "Link on Stripe: https://dashboard.stripe.com/customers/{$stripeCustomerId}\n"; + + continue; + } + $subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId); + if ($subscription->status === 'active') { + continue; + } + echo "Subscription {$stripeSubscriptionId} is not active ({$subscription->status})\n"; + echo "Link on Stripe: https://dashboard.stripe.com/subscriptions/{$stripeSubscriptionId}\n"; + } + } +} diff --git a/app/Console/Commands/Dev.php b/app/Console/Commands/Dev.php index f5f1233fe..05861a7de 100644 --- a/app/Console/Commands/Dev.php +++ b/app/Console/Commands/Dev.php @@ -6,6 +6,7 @@ use App\Models\InstanceSettings; use Illuminate\Console\Command; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Process; +use Symfony\Component\Yaml\Yaml; class Dev extends Command { @@ -37,6 +38,11 @@ class Dev extends Command $error = preg_replace('/^\h*\v+/m', '', $error); echo $error; echo $process->output(); + // Convert YAML to JSON + $yaml = file_get_contents('openapi.yaml'); + $json = json_encode(Yaml::parse($yaml), JSON_PRETTY_PRINT); + file_put_contents('openapi.json', $json); + echo "Converted OpenAPI YAML to JSON.\n"; } public function init() diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index c802fb116..e81b22ee6 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -57,12 +57,19 @@ class Init extends Command $this->call('cleanup:stucked-resources'); if (isCloud()) { - $response = Http::retry(3, 1000)->get(config('constants.services.official')); - if ($response->successful()) { - $services = $response->json(); - File::put(base_path('templates/service-templates.json'), json_encode($services)); + try { + $this->pullTemplatesFromCDN(); + } catch (\Throwable $e) { + echo "Could not pull templates from CDN: {$e->getMessage()}\n"; + } + } + + if (! isCloud()) { + try { + $this->pullTemplatesFromCDN(); + } catch (\Throwable $e) { + echo "Could not pull templates from CDN: {$e->getMessage()}\n"; } - } else { try { $localhost = $this->servers->where('id', 0)->first(); $localhost->setupDynamicProxyConfiguration(); @@ -80,6 +87,14 @@ class Init extends Command } } + private function pullTemplatesFromCDN() + { + $response = Http::retry(3, 1000)->get(config('constants.services.official')); + if ($response->successful()) { + $services = $response->json(); + File::put(base_path('templates/service-templates.json'), json_encode($services)); + } + } // private function disable_metrics() // { // if (version_compare('4.0.0-beta.312', config('version'), '<=')) { diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index b69028b70..1d89c82ed 100644 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -116,7 +116,7 @@ class ProjectController extends Controller responses: [ new OA\Response( response: 200, - description: 'Project details', + description: 'Environment details', content: new OA\JsonContent(ref: '#/components/schemas/Environment')), new OA\Response( response: 401, diff --git a/app/Http/Controllers/Api/SecurityController.php b/app/Http/Controllers/Api/SecurityController.php index bb474aed3..b7190ab1e 100644 --- a/app/Http/Controllers/Api/SecurityController.php +++ b/app/Http/Controllers/Api/SecurityController.php @@ -81,15 +81,8 @@ class SecurityController extends Controller new OA\Response( response: 200, description: 'Get all private keys.', - content: [ - new OA\MediaType( - mediaType: 'application/json', - schema: new OA\Schema( - type: 'array', - items: new OA\Items(ref: '#/components/schemas/PrivateKey') - ) - ), - ]), + content: new OA\JsonContent(ref: '#/components/schemas/PrivateKey') + ), new OA\Response( response: 401, ref: '#/components/responses/401', diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index 024ef35fa..cbee00642 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -426,6 +426,7 @@ class ServersController extends Controller 'private_key_uuid' => ['type' => 'string', 'example' => 'og888os', 'description' => 'The UUID of the private key.'], 'is_build_server' => ['type' => 'boolean', 'example' => false, 'description' => 'Is build server.'], 'instant_validate' => ['type' => 'boolean', 'example' => false, 'description' => 'Instant validate.'], + 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'example' => 'traefik', 'description' => 'The proxy type.'], ], ), ), @@ -461,7 +462,7 @@ class ServersController extends Controller )] public function create_server(Request $request) { - $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate']; + $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate', 'proxy_type']; $teamId = getTeamIdFromToken(); if (is_null($teamId)) { @@ -481,6 +482,7 @@ class ServersController extends Controller 'user' => 'string|nullable', 'is_build_server' => 'boolean|nullable', 'instant_validate' => 'boolean|nullable', + 'proxy_type' => 'string|nullable', ]); $extraFields = array_diff(array_keys($request->all()), $allowedFields); @@ -512,6 +514,14 @@ class ServersController extends Controller if (is_null($request->instant_validate)) { $request->offsetSet('instant_validate', false); } + if ($request->proxy_type) { + $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) { + return str($proxyType->value)->lower(); + }); + if (! $validProxyTypes->contains(str($request->proxy_type)->lower())) { + return response()->json(['message' => 'Invalid proxy type.'], 422); + } + } $privateKey = PrivateKey::whereTeamId($teamId)->whereUuid($request->private_key_uuid)->first(); if (! $privateKey) { return response()->json(['message' => 'Private key not found.'], 404); @@ -521,6 +531,8 @@ class ServersController extends Controller return response()->json(['message' => 'Server with this IP already exists.'], 400); } + $proxyType = $request->proxy_type ? str($request->proxy_type)->upper() : ProxyTypes::TRAEFIK->value; + $server = ModelsServer::create([ 'name' => $request->name, 'description' => $request->description, @@ -530,7 +542,7 @@ class ServersController extends Controller 'private_key_id' => $privateKey->id, 'team_id' => $teamId, 'proxy' => [ - 'type' => ProxyTypes::TRAEFIK->value, + 'type' => $proxyType, 'status' => ProxyStatus::EXITED->value, ], ]); @@ -571,6 +583,7 @@ class ServersController extends Controller 'private_key_uuid' => ['type' => 'string', 'description' => 'The UUID of the private key.'], 'is_build_server' => ['type' => 'boolean', 'description' => 'Is build server.'], 'instant_validate' => ['type' => 'boolean', 'description' => 'Instant validate.'], + 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'description' => 'The proxy type.'], ], ), ), @@ -604,7 +617,7 @@ class ServersController extends Controller )] public function update_server(Request $request) { - $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate']; + $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate', 'proxy_type']; $teamId = getTeamIdFromToken(); if (is_null($teamId)) { @@ -624,6 +637,7 @@ class ServersController extends Controller 'user' => 'string|nullable', 'is_build_server' => 'boolean|nullable', 'instant_validate' => 'boolean|nullable', + 'proxy_type' => 'string|nullable', ]); $extraFields = array_diff(array_keys($request->all()), $allowedFields); @@ -644,6 +658,16 @@ class ServersController extends Controller if (! $server) { return response()->json(['message' => 'Server not found.'], 404); } + if ($request->proxy_type) { + $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) { + return str($proxyType->value)->lower(); + }); + if ($validProxyTypes->contains(str($request->proxy_type)->lower())) { + $server->changeProxy($request->proxy_type, async: true); + } else { + return response()->json(['message' => 'Invalid proxy type.'], 422); + } + } $server->update($request->only(['name', 'description', 'ip', 'port', 'user'])); if ($request->is_build_server) { $server->settings()->update([ @@ -654,7 +678,9 @@ class ServersController extends Controller ValidateServer::dispatch($server)->onQueue('high'); } - return response()->json(serializeApiResponse($server))->setStatusCode(201); + return response()->json([ + + ])->setStatusCode(201); } #[OA\Delete( diff --git a/app/Http/Controllers/Webhook/Gitlab.php b/app/Http/Controllers/Webhook/Gitlab.php index f56711bad..d8dcc0c3b 100644 --- a/app/Http/Controllers/Webhook/Gitlab.php +++ b/app/Http/Controllers/Webhook/Gitlab.php @@ -33,6 +33,7 @@ class Gitlab extends Controller return; } + $return_payloads = collect([]); $payload = $request->collect(); $headers = $request->headers->all(); @@ -48,6 +49,15 @@ class Gitlab extends Controller return response($return_payloads); } + if (empty($x_gitlab_token)) { + $return_payloads->push([ + 'status' => 'failed', + 'message' => 'Invalid signature.', + ]); + + return response($return_payloads); + } + if ($x_gitlab_event === 'push') { $branch = data_get($payload, 'ref'); $full_name = data_get($payload, 'project.path_with_namespace'); diff --git a/app/Http/Controllers/Webhook/Stripe.php b/app/Http/Controllers/Webhook/Stripe.php index 5d297b242..e94209b23 100644 --- a/app/Http/Controllers/Webhook/Stripe.php +++ b/app/Http/Controllers/Webhook/Stripe.php @@ -5,8 +5,6 @@ namespace App\Http\Controllers\Webhook; use App\Http\Controllers\Controller; use App\Jobs\ServerLimitCheckJob; use App\Jobs\SubscriptionInvoiceFailedJob; -use App\Jobs\SubscriptionTrialEndedJob; -use App\Jobs\SubscriptionTrialEndsSoonJob; use App\Models\Subscription; use App\Models\Team; use App\Models\Webhook; @@ -260,42 +258,7 @@ class Stripe extends Controller $customerId = data_get($data, 'customer'); $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); $team = data_get($subscription, 'team'); - if ($team) { - $team->trialEnded(); - } - $subscription->update([ - 'stripe_subscription_id' => null, - 'stripe_plan_id' => null, - 'stripe_cancel_at_period_end' => false, - 'stripe_invoice_paid' => false, - 'stripe_trial_already_ended' => false, - ]); - // send_internal_notification('customer.subscription.deleted for customer: '.$customerId); - break; - case 'customer.subscription.trial_will_end': - // Not used for now - $customerId = data_get($data, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); - $team = data_get($subscription, 'team'); - if (! $team) { - return response('No team found for subscription: '.$subscription->id, 400); - } - SubscriptionTrialEndsSoonJob::dispatch($team); - break; - case 'customer.subscription.paused': - $customerId = data_get($data, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); - $team = data_get($subscription, 'team'); - if (! $team) { - return response('No team found for subscription: '.$subscription->id, 400); - } - $team->trialEnded(); - $subscription->update([ - 'stripe_trial_already_ended' => true, - 'stripe_invoice_paid' => false, - ]); - SubscriptionTrialEndedJob::dispatch($team); - // send_internal_notification('Subscription paused for customer: '.$customerId); + $team?->subscriptionEnded(); break; default: // Unhandled event type diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 27eded4f3..27f77f7a1 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -225,6 +225,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } } + public function tags(): array + { + return ['server:'.gethostname()]; + } + public function handle(): void { $this->application_deployment_queue->update([ diff --git a/app/Jobs/SubscriptionTrialEndedJob.php b/app/Jobs/SubscriptionTrialEndedJob.php deleted file mode 100755 index 88a5e06be..000000000 --- a/app/Jobs/SubscriptionTrialEndedJob.php +++ /dev/null @@ -1,42 +0,0 @@ -team); - $mail = new MailMessage; - $mail->subject('Action required: You trial in Coolify Cloud ended.'); - $mail->view('emails.trial-ended', [ - 'stripeCustomerPortal' => $session->url, - ]); - $this->team->members()->each(function ($member) use ($mail) { - if ($member->isAdmin()) { - send_user_an_email($mail, $member->email); - send_internal_notification('Trial reminder email sent to '.$member->email); - } - }); - } catch (\Throwable $e) { - send_internal_notification('SubscriptionTrialEndsSoonJob failed with: '.$e->getMessage()); - throw $e; - } - } -} diff --git a/app/Jobs/SubscriptionTrialEndsSoonJob.php b/app/Jobs/SubscriptionTrialEndsSoonJob.php deleted file mode 100755 index 2a76a1097..000000000 --- a/app/Jobs/SubscriptionTrialEndsSoonJob.php +++ /dev/null @@ -1,42 +0,0 @@ -team); - $mail = new MailMessage; - $mail->subject('You trial in Coolify Cloud ends soon.'); - $mail->view('emails.trial-ends-soon', [ - 'stripeCustomerPortal' => $session->url, - ]); - $this->team->members()->each(function ($member) use ($mail) { - if ($member->isAdmin()) { - send_user_an_email($mail, $member->email); - send_internal_notification('Trial reminder email sent to '.$member->email); - } - }); - } catch (\Throwable $e) { - send_internal_notification('SubscriptionTrialEndsSoonJob failed with: '.$e->getMessage()); - throw $e; - } - } -} diff --git a/app/Livewire/Admin/Index.php b/app/Livewire/Admin/Index.php index 2579c3db2..359db6329 100644 --- a/app/Livewire/Admin/Index.php +++ b/app/Livewire/Admin/Index.php @@ -2,8 +2,8 @@ namespace App\Livewire\Admin; +use App\Models\Team; use App\Models\User; -use Illuminate\Container\Attributes\Auth as AttributesAuth; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Cache; @@ -43,17 +43,13 @@ class Index extends Component public function getSubscribers() { - $this->inactiveSubscribers = User::whereDoesntHave('teams', function ($query) { - $query->whereRelation('subscription', 'stripe_subscription_id', '!=', null); - })->count(); - $this->activeSubscribers = User::whereHas('teams', function ($query) { - $query->whereRelation('subscription', 'stripe_subscription_id', '!=', null); - })->count(); + $this->inactiveSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', false)->count(); + $this->activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->count(); } public function switchUser(int $user_id) { - if (AttributesAuth::id() !== 0) { + if (Auth::id() !== 0) { return redirect()->route('dashboard'); } $user = User::find($user_id); diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php index c9c3092b3..b6c799c4e 100644 --- a/app/Livewire/Boarding/Index.php +++ b/app/Livewire/Boarding/Index.php @@ -66,11 +66,15 @@ class Index extends Component public bool $serverReachable = true; + public ?string $minDockerVersion = null; + public function mount() { if (auth()->user()?->isMember() && auth()->user()->currentTeam()->show_boarding === true) { return redirect()->route('dashboard'); } + + $this->minDockerVersion = str(config('constants.docker.minimum_required_version'))->before('.'); $this->privateKeyName = generate_random_name(); $this->remoteServerName = generate_random_name(); if (isDev()) { diff --git a/app/Livewire/Server/Proxy.php b/app/Livewire/Server/Proxy.php index 94ea3509a..0b069ddb9 100644 --- a/app/Livewire/Server/Proxy.php +++ b/app/Livewire/Server/Proxy.php @@ -4,7 +4,6 @@ namespace App\Livewire\Server; use App\Actions\Proxy\CheckConfiguration; use App\Actions\Proxy\SaveConfiguration; -use App\Actions\Proxy\StartProxy; use App\Models\Server; use Livewire\Component; @@ -44,14 +43,13 @@ class Proxy extends Component public function selectProxy($proxy_type) { - $this->server->proxy->set('status', 'exited'); - $this->server->proxy->set('type', $proxy_type); - $this->server->save(); - $this->selectedProxy = $this->server->proxy->type; - if ($this->server->proxySet()) { - StartProxy::run($this->server, false); + try { + $this->server->changeProxy($proxy_type, async: false); + $this->selectedProxy = $this->server->proxy->type; + $this->dispatch('proxyStatusUpdated'); + } catch (\Throwable $e) { + return handleError($e, $this); } - $this->dispatch('proxyStatusUpdated'); } public function instantSave() diff --git a/app/Livewire/Server/ValidateAndInstall.php b/app/Livewire/Server/ValidateAndInstall.php index 8c5bc23ed..791ef9350 100644 --- a/app/Livewire/Server/ValidateAndInstall.php +++ b/app/Livewire/Server/ValidateAndInstall.php @@ -159,7 +159,8 @@ class ValidateAndInstall extends Component $this->dispatch('refreshBoardingIndex'); $this->dispatch('success', 'Server validated.'); } else { - $this->error = 'Docker Engine version is not 22+. Please install Docker manually before continuing: documentation.'; + $requiredDockerVersion = str(config('constants.docker.minimum_required_version'))->before('.'); + $this->error = 'Minimum Docker Engine version '.$requiredDockerVersion.' is not instaled. Please install Docker manually before continuing: documentation.'; $this->server->update([ 'validation_logs' => $this->error, ]); diff --git a/app/Livewire/Terminal/Index.php b/app/Livewire/Terminal/Index.php index 945b25714..a24a237c5 100644 --- a/app/Livewire/Terminal/Index.php +++ b/app/Livewire/Terminal/Index.php @@ -14,13 +14,25 @@ class Index extends Component public $containers = []; + public bool $isLoadingContainers = true; + public function mount() { if (! auth()->user()->isAdmin()) { abort(403); } $this->servers = Server::isReachable()->get(); - $this->containers = $this->getAllActiveContainers(); + } + + public function loadContainers() + { + try { + $this->containers = $this->getAllActiveContainers(); + } catch (\Exception $e) { + return handleError($e, $this); + } finally { + $this->isLoadingContainers = false; + } } private function getAllActiveContainers() diff --git a/app/Models/Application.php b/app/Models/Application.php index 64244c900..c284528f1 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -906,21 +906,7 @@ class Application extends BaseModel public function customRepository() { - preg_match('/(?<=:)\d+(?=\/)/', $this->git_repository, $matches); - $port = 22; - if (count($matches) === 1) { - $port = $matches[0]; - $gitHost = str($this->git_repository)->before(':'); - $gitRepo = str($this->git_repository)->after('/'); - $repository = "$gitHost:$gitRepo"; - } else { - $repository = $this->git_repository; - } - - return [ - 'repository' => $repository, - 'port' => $port, - ]; + return convertGitUrl($this->git_repository, $this->deploymentType(), $this->source); } public function generateBaseDir(string $uuid) @@ -953,6 +939,122 @@ class Application extends BaseModel return $git_clone_command; } + public function getGitRemoteStatus(string $deployment_uuid) + { + try { + ['commands' => $lsRemoteCommand] = $this->generateGitLsRemoteCommands(deployment_uuid: $deployment_uuid, exec_in_docker: false); + instant_remote_process([$lsRemoteCommand], $this->destination->server, true); + + return [ + 'is_accessible' => true, + 'error' => null, + ]; + } catch (\RuntimeException $ex) { + return [ + 'is_accessible' => false, + 'error' => $ex->getMessage(), + ]; + } + } + + public function generateGitLsRemoteCommands(string $deployment_uuid, bool $exec_in_docker = true) + { + $branch = $this->git_branch; + ['repository' => $customRepository, 'port' => $customPort] = $this->customRepository(); + $commands = collect([]); + $base_command = 'git ls-remote'; + + if ($this->deploymentType() === 'source') { + $source_html_url = data_get($this, 'source.html_url'); + $url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL)); + $source_html_url_host = $url['host']; + $source_html_url_scheme = $url['scheme']; + + if ($this->source->getMorphClass() == 'App\Models\GithubApp') { + if ($this->source->is_public) { + $fullRepoUrl = "{$this->source->html_url}/{$customRepository}"; + $base_command = "{$base_command} {$this->source->html_url}/{$customRepository}"; + } else { + $github_access_token = generate_github_installation_token($this->source); + + if ($exec_in_docker) { + $base_command = "{$base_command} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git"; + $fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}.git"; + } else { + $base_command = "{$base_command} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}"; + $fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$customRepository}"; + } + } + + if ($exec_in_docker) { + $commands->push(executeInDocker($deployment_uuid, $base_command)); + } else { + $commands->push($base_command); + } + + return [ + 'commands' => $commands->implode(' && '), + 'branch' => $branch, + 'fullRepoUrl' => $fullRepoUrl, + ]; + } + } + + if ($this->deploymentType() === 'deploy_key') { + $fullRepoUrl = $customRepository; + $private_key = data_get($this, 'private_key.private_key'); + if (is_null($private_key)) { + throw new RuntimeException('Private key not found. Please add a private key to the application and try again.'); + } + $private_key = base64_encode($private_key); + $base_comamnd = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$customPort} -o Port={$customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$base_command} {$customRepository}"; + + if ($exec_in_docker) { + $commands = collect([ + executeInDocker($deployment_uuid, 'mkdir -p /root/.ssh'), + executeInDocker($deployment_uuid, "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null"), + executeInDocker($deployment_uuid, 'chmod 600 /root/.ssh/id_rsa'), + ]); + } else { + $commands = collect([ + 'mkdir -p /root/.ssh', + "echo '{$private_key}' | base64 -d | tee /root/.ssh/id_rsa > /dev/null", + 'chmod 600 /root/.ssh/id_rsa', + ]); + } + + if ($exec_in_docker) { + $commands->push(executeInDocker($deployment_uuid, $base_comamnd)); + } else { + $commands->push($base_comamnd); + } + + return [ + 'commands' => $commands->implode(' && '), + 'branch' => $branch, + 'fullRepoUrl' => $fullRepoUrl, + ]; + } + + if ($this->deploymentType() === 'other') { + $fullRepoUrl = $customRepository; + $base_command = "{$base_command} {$customRepository}"; + $base_command = $this->setGitImportSettings($deployment_uuid, $base_command, public: true); + + if ($exec_in_docker) { + $commands->push(executeInDocker($deployment_uuid, $base_command)); + } else { + $commands->push($base_command); + } + + return [ + 'commands' => $commands->implode(' && '), + 'branch' => $branch, + 'fullRepoUrl' => $fullRepoUrl, + ]; + } + } + public function generateGitImportCommands(string $deployment_uuid, int $pull_request_id = 0, ?string $git_type = null, bool $exec_in_docker = true, bool $only_checkout = false, ?string $custom_base_dir = null, ?string $commit = null) { $branch = $this->git_branch; @@ -1214,6 +1316,11 @@ class Application extends BaseModel $workdir = rtrim($this->base_directory, '/'); $composeFile = $this->docker_compose_location; $fileList = collect([".$workdir$composeFile"]); + $gitRemoteStatus = $this->getGitRemoteStatus(deployment_uuid: $uuid); + if (! $gitRemoteStatus['is_accessible']) { + throw new \RuntimeException("Failed to read Git source:\n\n{$gitRemoteStatus['error']}"); + } + $commands = collect([ "rm -rf /tmp/{$uuid}", "mkdir -p /tmp/{$uuid}", diff --git a/app/Models/Server.php b/app/Models/Server.php index 64192c71f..f33f80863 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Actions\Proxy\StartProxy; use App\Actions\Server\InstallDocker; use App\Actions\Server\StartSentinel; use App\Enums\ProxyTypes; @@ -26,22 +27,23 @@ use Symfony\Component\Yaml\Yaml; description: 'Server model', type: 'object', properties: [ - 'id' => ['type' => 'integer'], - 'uuid' => ['type' => 'string'], - 'name' => ['type' => 'string'], - 'description' => ['type' => 'string'], - 'ip' => ['type' => 'string'], - 'user' => ['type' => 'string'], - 'port' => ['type' => 'integer'], - 'proxy' => ['type' => 'object'], - 'high_disk_usage_notification_sent' => ['type' => 'boolean'], - 'unreachable_notification_sent' => ['type' => 'boolean'], - 'unreachable_count' => ['type' => 'integer'], - 'validation_logs' => ['type' => 'string'], - 'log_drain_notification_sent' => ['type' => 'boolean'], - 'swarm_cluster' => ['type' => 'string'], - 'delete_unused_volumes' => ['type' => 'boolean'], - 'delete_unused_networks' => ['type' => 'boolean'], + 'id' => ['type' => 'integer', 'description' => 'The server ID.'], + 'uuid' => ['type' => 'string', 'description' => 'The server UUID.'], + 'name' => ['type' => 'string', 'description' => 'The server name.'], + 'description' => ['type' => 'string', 'description' => 'The server description.'], + 'ip' => ['type' => 'string', 'description' => 'The IP address.'], + 'user' => ['type' => 'string', 'description' => 'The user.'], + 'port' => ['type' => 'integer', 'description' => 'The port number.'], + 'proxy' => ['type' => 'object', 'description' => 'The proxy configuration.'], + 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'description' => 'The proxy type.'], + 'high_disk_usage_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the high disk usage notification has been sent.'], + 'unreachable_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unreachable notification has been sent.'], + 'unreachable_count' => ['type' => 'integer', 'description' => 'The unreachable count for your server.'], + 'validation_logs' => ['type' => 'string', 'description' => 'The validation logs.'], + 'log_drain_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the log drain notification has been sent.'], + 'swarm_cluster' => ['type' => 'string', 'description' => 'The swarm cluster configuration.'], + 'delete_unused_volumes' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unused volumes should be deleted.'], + 'delete_unused_networks' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unused networks should be deleted.'], ] )] @@ -1251,4 +1253,25 @@ $schema://$host { { return instant_remote_process(['docker restart '.$containerName], $this, false); } + + public function changeProxy(string $proxyType, bool $async = true) + { + $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) { + return str($proxyType->value)->lower(); + }); + if ($validProxyTypes->contains(str($proxyType)->lower())) { + $this->proxy->set('type', str($proxyType)->upper()); + $this->proxy->set('status', 'exited'); + $this->save(); + if ($this->proxySet()) { + if ($async) { + StartProxy::dispatch($this); + } else { + StartProxy::run($this); + } + } + } else { + throw new \Exception('Invalid proxy type.'); + } + } } diff --git a/app/Models/Team.php b/app/Models/Team.php index db485054b..8996b745c 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -257,8 +257,15 @@ class Team extends Model implements SendsDiscord, SendsEmail return $this->hasMany(S3Storage::class)->where('is_usable', true); } - public function trialEnded() + public function subscriptionEnded() { + $this->subscription->update([ + 'stripe_subscription_id' => null, + 'stripe_plan_id' => null, + 'stripe_cancel_at_period_end' => false, + 'stripe_invoice_paid' => false, + 'stripe_trial_already_ended' => false, + ]); foreach ($this->servers as $server) { $server->settings()->update([ 'is_usable' => false, @@ -267,16 +274,6 @@ class Team extends Model implements SendsDiscord, SendsEmail } } - public function trialEndedButSubscribed() - { - foreach ($this->servers as $server) { - $server->settings()->update([ - 'is_usable' => true, - 'is_reachable' => true, - ]); - } - } - public function isAnyNotificationEnabled() { if (isCloud()) { diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index ca933e6ae..6a3c7f621 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -109,7 +109,8 @@ function format_docker_envs_to_json($rawOutput) function checkMinimumDockerEngineVersion($dockerVersion) { $majorDockerVersion = str($dockerVersion)->before('.')->value(); - if ($majorDockerVersion <= 22) { + $requiredDockerVersion = str(config('constants.docker.minimum_required_version'))->before('.')->value(); + if ($majorDockerVersion < $requiredDockerVersion) { $dockerVersion = null; } @@ -225,15 +226,13 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource) case $type?->contains('minio'): $MINIO_BROWSER_REDIRECT_URL = $variables->where('key', 'MINIO_BROWSER_REDIRECT_URL')->first(); $MINIO_SERVER_URL = $variables->where('key', 'MINIO_SERVER_URL')->first(); - if (is_null($MINIO_BROWSER_REDIRECT_URL) || is_null($MINIO_SERVER_URL)) { - return $payload; - } - if (is_null($MINIO_BROWSER_REDIRECT_URL?->value)) { + + if (str($MINIO_BROWSER_REDIRECT_URL->value)->isEmpty()) { $MINIO_BROWSER_REDIRECT_URL?->update([ 'value' => generateFqdn($server, 'console-'.$uuid, true), ]); } - if (is_null($MINIO_SERVER_URL?->value)) { + if (str($MINIO_SERVER_URL->value)->isEmpty()) { $MINIO_SERVER_URL?->update([ 'value' => generateFqdn($server, 'minio-'.$uuid, true), ]); @@ -246,15 +245,13 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource) case $type?->contains('logto'): $LOGTO_ENDPOINT = $variables->where('key', 'LOGTO_ENDPOINT')->first(); $LOGTO_ADMIN_ENDPOINT = $variables->where('key', 'LOGTO_ADMIN_ENDPOINT')->first(); - if (is_null($LOGTO_ENDPOINT) || is_null($LOGTO_ADMIN_ENDPOINT)) { - return $payload; - } - if (is_null($LOGTO_ENDPOINT?->value)) { + + if (str($LOGTO_ENDPOINT?->value)->isEmpty()) { $LOGTO_ENDPOINT?->update([ 'value' => generateFqdn($server, 'logto-'.$uuid), ]); } - if (is_null($LOGTO_ADMIN_ENDPOINT?->value)) { + if (str($LOGTO_ADMIN_ENDPOINT?->value)->isEmpty()) { $LOGTO_ADMIN_ENDPOINT?->update([ 'value' => generateFqdn($server, 'logto-admin-'.$uuid), ]); diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 2f0a3ac2a..6e52dcde9 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -7,6 +7,7 @@ use App\Models\Application; use App\Models\ApplicationDeploymentQueue; use App\Models\ApplicationPreview; use App\Models\EnvironmentVariable; +use App\Models\GithubApp; use App\Models\InstanceSettings; use App\Models\LocalFileVolume; use App\Models\LocalPersistentVolume; @@ -4092,3 +4093,53 @@ function defaultNginxConfiguration(): string } }'; } + +function convertGitUrl(string $gitRepository, string $deploymentType, ?GithubApp $source = null): array +{ + $repository = $gitRepository; + $providerInfo = [ + 'host' => null, + 'user' => 'git', + 'port' => 22, + 'repository' => $gitRepository, + ]; + $sshMatches = []; + $matches = []; + + // Let's try and parse the string to detect if it's a valid SSH string or not + preg_match('/((.*?)\:\/\/)?(.*@.*:.*)/', $gitRepository, $sshMatches); + + if ($deploymentType === 'deploy_key' && empty($sshMatches) && $source) { + // If this happens, the user may have provided an HTTP URL when they needed an SSH one + // Let's try and fix that for known Git providers + switch ($source->getMorphClass()) { + case \App\Models\GithubApp::class: + $providerInfo['host'] = Url::fromString($source->html_url)->getHost(); + $providerInfo['port'] = $source->custom_port; + $providerInfo['user'] = $source->custom_user; + break; + } + if (! empty($providerInfo['host'])) { + // Until we do not support more providers with App (like GithubApp), this will be always true, port will be 22 + if ($providerInfo['port'] === 22) { + $repository = "{$providerInfo['user']}@{$providerInfo['host']}:{$providerInfo['repository']}"; + } else { + $repository = "ssh://{$providerInfo['user']}@{$providerInfo['host']}:{$providerInfo['port']}/{$providerInfo['repository']}"; + } + } + } + + preg_match('/(?<=:)\d+(?=\/)/', $gitRepository, $matches); + + if (count($matches) === 1) { + $providerInfo['port'] = $matches[0]; + $gitHost = str($gitRepository)->before(':'); + $gitRepo = str($gitRepository)->after('/'); + $repository = "$gitHost:$gitRepo"; + } + + return [ + 'repository' => $repository, + 'port' => $providerInfo['port'], + ]; +} diff --git a/composer.json b/composer.json index 2bae1149c..4ba2279c6 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ ], "require": { "php": "^8.2", + "3sidedcube/laravel-redoc": "^1.0", "danharrin/livewire-rate-limiting": "^1.1", "doctrine/dbal": "^3.6", "guzzlehttp/guzzle": "^7.5.0", @@ -119,4 +120,4 @@ "@php artisan key:generate --ansi" ] } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index 5eb03b5fc..50bcdf672 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,66 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3f2342fe6b1ba920c8875f8a8fe41962", + "content-hash": "b9f4772191b4680e6f92fa9c7c396b10", "packages": [ + { + "name": "3sidedcube/laravel-redoc", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/3sidedcube/laravel-redoc.git", + "reference": "c33a563885dcdf1e0f623df5a56c106d130261da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/3sidedcube/laravel-redoc/zipball/c33a563885dcdf1e0f623df5a56c106d130261da", + "reference": "c33a563885dcdf1e0f623df5a56c106d130261da", + "shasum": "" + }, + "require": { + "illuminate/routing": "^8.0|^9.0|^10.0|^11.0", + "illuminate/support": "^8.0|^9.0|^10.0|^11.0", + "php": "^7.4|^8.0|^8.1|^8.2|^8.3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.3", + "orchestra/testbench": "^6.0|^7.0|^8.0|^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "ThreeSidedCube\\LaravelRedoc\\RedocServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "ThreeSidedCube\\LaravelRedoc\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Sherred", + "role": "Developer" + } + ], + "description": "A lightweight package for rendering API documentation using OpenAPI and Redoc.", + "homepage": "https://github.com/3sidedcube/laravel-redoc", + "keywords": [ + "3sidedcube", + "laravel-redoc" + ], + "support": { + "issues": "https://github.com/3sidedcube/laravel-redoc/issues", + "source": "https://github.com/3sidedcube/laravel-redoc/tree/v1.0.1" + }, + "time": "2024-05-20T11:37:55+00:00" + }, { "name": "amphp/amp", "version": "v3.0.2", diff --git a/config/constants.php b/config/constants.php index 1bec2e3bf..7f41ee868 100644 --- a/config/constants.php +++ b/config/constants.php @@ -1,7 +1,6 @@ '26.0', 'docs' => [ 'base_url' => 'https://coolify.io/docs', 'contact' => 'https://coolify.io/docs/contact', @@ -13,6 +12,9 @@ return [ 'server_interval' => 20, 'command_timeout' => 7200, ], + 'docker' => [ + 'minimum_required_version' => '26.0', + ], 'waitlist' => [ 'expiration' => 10, ], diff --git a/config/redoc.php b/config/redoc.php new file mode 100644 index 000000000..439e93e7b --- /dev/null +++ b/config/redoc.php @@ -0,0 +1,28 @@ + '', + + /* + |-------------------------------------------------------------------------- + | Variables + |-------------------------------------------------------------------------- + | + | You can automatically replace variables in your OpenAPI definitions by + | adding a key value pair to the array below. This will replace any + | instances of :key with the given value. + | + */ + + 'variables' => [], + +]; diff --git a/config/sentry.php b/config/sentry.php index 117a0e6d8..232070705 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // 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.367', + 'release' => '4.0.0-beta.368', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index 3b32ad4af..ddb1cb354 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ non-www.", + "enum": [ + "www", + "non-www", + "both" + ] + }, + "instant_deploy": { + "type": "boolean", + "description": "The flag to indicate if the application should be deployed instantly." + }, + "dockerfile": { + "type": "string", + "description": "The Dockerfile content." + }, + "docker_compose_location": { + "type": "string", + "description": "The Docker Compose location." + }, + "docker_compose_raw": { + "type": "string", + "description": "The Docker Compose raw content." + }, + "docker_compose_custom_start_command": { + "type": "string", + "description": "The Docker Compose custom start command." + }, + "docker_compose_custom_build_command": { + "type": "string", + "description": "The Docker Compose custom build command." + }, + "docker_compose_domains": { + "type": "array", + "description": "The Docker Compose domains." + }, + "watch_paths": { + "type": "string", + "description": "The watch paths." + }, + "use_build_server": { + "type": "boolean", + "nullable": true, + "description": "Use build server." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Application created successfully." + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/private-github-app": { + "post": { + "tags": [ + "Applications" + ], + "summary": "Create (Private - GH App)", + "description": "Create new application based on a private repository through a Github App.", + "operationId": "create-private-github-app-application", + "requestBody": { + "description": "Application object that needs to be created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "project_uuid", + "server_uuid", + "environment_name", + "github_app_uuid", + "git_repository", + "git_branch", + "build_pack", + "ports_exposes" + ], + "properties": { + "project_uuid": { + "type": "string", + "description": "The project UUID." + }, + "server_uuid": { + "type": "string", + "description": "The server UUID." + }, + "environment_name": { + "type": "string", + "description": "The environment name." + }, + "github_app_uuid": { + "type": "string", + "description": "The Github App UUID." + }, + "git_repository": { + "type": "string", + "description": "The git repository URL." + }, + "git_branch": { + "type": "string", + "description": "The git branch." + }, + "ports_exposes": { + "type": "string", + "description": "The ports to expose." + }, + "destination_uuid": { + "type": "string", + "description": "The destination UUID." + }, + "build_pack": { + "type": "string", + "enum": [ + "nixpacks", + "static", + "dockerfile", + "dockercompose" + ], + "description": "The build pack type." + }, + "name": { + "type": "string", + "description": "The application name." + }, + "description": { + "type": "string", + "description": "The application description." + }, + "domains": { + "type": "string", + "description": "The application domains." + }, + "git_commit_sha": { + "type": "string", + "description": "The git commit SHA." + }, + "docker_registry_image_name": { + "type": "string", + "description": "The docker registry image name." + }, + "docker_registry_image_tag": { + "type": "string", + "description": "The docker registry image tag." + }, + "is_static": { + "type": "boolean", + "description": "The flag to indicate if the application is static." + }, + "static_image": { + "type": "string", + "enum": [ + "nginx:alpine" + ], + "description": "The static image." + }, + "install_command": { + "type": "string", + "description": "The install command." + }, + "build_command": { + "type": "string", + "description": "The build command." + }, + "start_command": { + "type": "string", + "description": "The start command." + }, + "ports_mappings": { + "type": "string", + "description": "The ports mappings." + }, + "base_directory": { + "type": "string", + "description": "The base directory for all commands." + }, + "publish_directory": { + "type": "string", + "description": "The publish directory." + }, + "health_check_enabled": { + "type": "boolean", + "description": "Health check enabled." + }, + "health_check_path": { + "type": "string", + "description": "Health check path." + }, + "health_check_port": { + "type": "string", + "nullable": true, + "description": "Health check port." + }, + "health_check_host": { + "type": "string", + "nullable": true, + "description": "Health check host." + }, + "health_check_method": { + "type": "string", + "description": "Health check method." + }, + "health_check_return_code": { + "type": "integer", + "description": "Health check return code." + }, + "health_check_scheme": { + "type": "string", + "description": "Health check scheme." + }, + "health_check_response_text": { + "type": "string", + "nullable": true, + "description": "Health check response text." + }, + "health_check_interval": { + "type": "integer", + "description": "Health check interval in seconds." + }, + "health_check_timeout": { + "type": "integer", + "description": "Health check timeout in seconds." + }, + "health_check_retries": { + "type": "integer", + "description": "Health check retries count." + }, + "health_check_start_period": { + "type": "integer", + "description": "Health check start period in seconds." + }, + "limits_memory": { + "type": "string", + "description": "Memory limit." + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit." + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness." + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation." + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit." + }, + "limits_cpuset": { + "type": "string", + "nullable": true, + "description": "CPU set." + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares." + }, + "custom_labels": { + "type": "string", + "description": "Custom labels." + }, + "custom_docker_run_options": { + "type": "string", + "description": "Custom docker run options." + }, + "post_deployment_command": { + "type": "string", + "description": "Post deployment command." + }, + "post_deployment_command_container": { + "type": "string", + "description": "Post deployment command container." + }, + "pre_deployment_command": { + "type": "string", + "description": "Pre deployment command." + }, + "pre_deployment_command_container": { + "type": "string", + "description": "Pre deployment command container." + }, + "manual_webhook_secret_github": { + "type": "string", + "description": "Manual webhook secret for Github." + }, + "manual_webhook_secret_gitlab": { + "type": "string", + "description": "Manual webhook secret for Gitlab." + }, + "manual_webhook_secret_bitbucket": { + "type": "string", + "description": "Manual webhook secret for Bitbucket." + }, + "manual_webhook_secret_gitea": { + "type": "string", + "description": "Manual webhook secret for Gitea." + }, + "redirect": { + "type": "string", + "nullable": true, + "description": "How to set redirect with Traefik \/ Caddy. www<->non-www.", + "enum": [ + "www", + "non-www", + "both" + ] + }, + "instant_deploy": { + "type": "boolean", + "description": "The flag to indicate if the application should be deployed instantly." + }, + "dockerfile": { + "type": "string", + "description": "The Dockerfile content." + }, + "docker_compose_location": { + "type": "string", + "description": "The Docker Compose location." + }, + "docker_compose_raw": { + "type": "string", + "description": "The Docker Compose raw content." + }, + "docker_compose_custom_start_command": { + "type": "string", + "description": "The Docker Compose custom start command." + }, + "docker_compose_custom_build_command": { + "type": "string", + "description": "The Docker Compose custom build command." + }, + "docker_compose_domains": { + "type": "array", + "description": "The Docker Compose domains." + }, + "watch_paths": { + "type": "string", + "description": "The watch paths." + }, + "use_build_server": { + "type": "boolean", + "nullable": true, + "description": "Use build server." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Application created successfully." + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/private-deploy-key": { + "post": { + "tags": [ + "Applications" + ], + "summary": "Create (Private - Deploy Key)", + "description": "Create new application based on a private repository through a Deploy Key.", + "operationId": "create-private-deploy-key-application", + "requestBody": { + "description": "Application object that needs to be created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "project_uuid", + "server_uuid", + "environment_name", + "private_key_uuid", + "git_repository", + "git_branch", + "build_pack", + "ports_exposes" + ], + "properties": { + "project_uuid": { + "type": "string", + "description": "The project UUID." + }, + "server_uuid": { + "type": "string", + "description": "The server UUID." + }, + "environment_name": { + "type": "string", + "description": "The environment name." + }, + "private_key_uuid": { + "type": "string", + "description": "The private key UUID." + }, + "git_repository": { + "type": "string", + "description": "The git repository URL." + }, + "git_branch": { + "type": "string", + "description": "The git branch." + }, + "ports_exposes": { + "type": "string", + "description": "The ports to expose." + }, + "destination_uuid": { + "type": "string", + "description": "The destination UUID." + }, + "build_pack": { + "type": "string", + "enum": [ + "nixpacks", + "static", + "dockerfile", + "dockercompose" + ], + "description": "The build pack type." + }, + "name": { + "type": "string", + "description": "The application name." + }, + "description": { + "type": "string", + "description": "The application description." + }, + "domains": { + "type": "string", + "description": "The application domains." + }, + "git_commit_sha": { + "type": "string", + "description": "The git commit SHA." + }, + "docker_registry_image_name": { + "type": "string", + "description": "The docker registry image name." + }, + "docker_registry_image_tag": { + "type": "string", + "description": "The docker registry image tag." + }, + "is_static": { + "type": "boolean", + "description": "The flag to indicate if the application is static." + }, + "static_image": { + "type": "string", + "enum": [ + "nginx:alpine" + ], + "description": "The static image." + }, + "install_command": { + "type": "string", + "description": "The install command." + }, + "build_command": { + "type": "string", + "description": "The build command." + }, + "start_command": { + "type": "string", + "description": "The start command." + }, + "ports_mappings": { + "type": "string", + "description": "The ports mappings." + }, + "base_directory": { + "type": "string", + "description": "The base directory for all commands." + }, + "publish_directory": { + "type": "string", + "description": "The publish directory." + }, + "health_check_enabled": { + "type": "boolean", + "description": "Health check enabled." + }, + "health_check_path": { + "type": "string", + "description": "Health check path." + }, + "health_check_port": { + "type": "string", + "nullable": true, + "description": "Health check port." + }, + "health_check_host": { + "type": "string", + "nullable": true, + "description": "Health check host." + }, + "health_check_method": { + "type": "string", + "description": "Health check method." + }, + "health_check_return_code": { + "type": "integer", + "description": "Health check return code." + }, + "health_check_scheme": { + "type": "string", + "description": "Health check scheme." + }, + "health_check_response_text": { + "type": "string", + "nullable": true, + "description": "Health check response text." + }, + "health_check_interval": { + "type": "integer", + "description": "Health check interval in seconds." + }, + "health_check_timeout": { + "type": "integer", + "description": "Health check timeout in seconds." + }, + "health_check_retries": { + "type": "integer", + "description": "Health check retries count." + }, + "health_check_start_period": { + "type": "integer", + "description": "Health check start period in seconds." + }, + "limits_memory": { + "type": "string", + "description": "Memory limit." + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit." + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness." + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation." + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit." + }, + "limits_cpuset": { + "type": "string", + "nullable": true, + "description": "CPU set." + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares." + }, + "custom_labels": { + "type": "string", + "description": "Custom labels." + }, + "custom_docker_run_options": { + "type": "string", + "description": "Custom docker run options." + }, + "post_deployment_command": { + "type": "string", + "description": "Post deployment command." + }, + "post_deployment_command_container": { + "type": "string", + "description": "Post deployment command container." + }, + "pre_deployment_command": { + "type": "string", + "description": "Pre deployment command." + }, + "pre_deployment_command_container": { + "type": "string", + "description": "Pre deployment command container." + }, + "manual_webhook_secret_github": { + "type": "string", + "description": "Manual webhook secret for Github." + }, + "manual_webhook_secret_gitlab": { + "type": "string", + "description": "Manual webhook secret for Gitlab." + }, + "manual_webhook_secret_bitbucket": { + "type": "string", + "description": "Manual webhook secret for Bitbucket." + }, + "manual_webhook_secret_gitea": { + "type": "string", + "description": "Manual webhook secret for Gitea." + }, + "redirect": { + "type": "string", + "nullable": true, + "description": "How to set redirect with Traefik \/ Caddy. www<->non-www.", + "enum": [ + "www", + "non-www", + "both" + ] + }, + "instant_deploy": { + "type": "boolean", + "description": "The flag to indicate if the application should be deployed instantly." + }, + "dockerfile": { + "type": "string", + "description": "The Dockerfile content." + }, + "docker_compose_location": { + "type": "string", + "description": "The Docker Compose location." + }, + "docker_compose_raw": { + "type": "string", + "description": "The Docker Compose raw content." + }, + "docker_compose_custom_start_command": { + "type": "string", + "description": "The Docker Compose custom start command." + }, + "docker_compose_custom_build_command": { + "type": "string", + "description": "The Docker Compose custom build command." + }, + "docker_compose_domains": { + "type": "array", + "description": "The Docker Compose domains." + }, + "watch_paths": { + "type": "string", + "description": "The watch paths." + }, + "use_build_server": { + "type": "boolean", + "nullable": true, + "description": "Use build server." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Application created successfully." + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/dockerfile": { + "post": { + "tags": [ + "Applications" + ], + "summary": "Create (Dockerfile)", + "description": "Create new application based on a simple Dockerfile.", + "operationId": "create-dockerfile-application", + "requestBody": { + "description": "Application object that needs to be created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "project_uuid", + "server_uuid", + "environment_name", + "dockerfile" + ], + "properties": { + "project_uuid": { + "type": "string", + "description": "The project UUID." + }, + "server_uuid": { + "type": "string", + "description": "The server UUID." + }, + "environment_name": { + "type": "string", + "description": "The environment name." + }, + "dockerfile": { + "type": "string", + "description": "The Dockerfile content." + }, + "build_pack": { + "type": "string", + "enum": [ + "nixpacks", + "static", + "dockerfile", + "dockercompose" + ], + "description": "The build pack type." + }, + "ports_exposes": { + "type": "string", + "description": "The ports to expose." + }, + "destination_uuid": { + "type": "string", + "description": "The destination UUID." + }, + "name": { + "type": "string", + "description": "The application name." + }, + "description": { + "type": "string", + "description": "The application description." + }, + "domains": { + "type": "string", + "description": "The application domains." + }, + "docker_registry_image_name": { + "type": "string", + "description": "The docker registry image name." + }, + "docker_registry_image_tag": { + "type": "string", + "description": "The docker registry image tag." + }, + "ports_mappings": { + "type": "string", + "description": "The ports mappings." + }, + "base_directory": { + "type": "string", + "description": "The base directory for all commands." + }, + "health_check_enabled": { + "type": "boolean", + "description": "Health check enabled." + }, + "health_check_path": { + "type": "string", + "description": "Health check path." + }, + "health_check_port": { + "type": "string", + "nullable": true, + "description": "Health check port." + }, + "health_check_host": { + "type": "string", + "nullable": true, + "description": "Health check host." + }, + "health_check_method": { + "type": "string", + "description": "Health check method." + }, + "health_check_return_code": { + "type": "integer", + "description": "Health check return code." + }, + "health_check_scheme": { + "type": "string", + "description": "Health check scheme." + }, + "health_check_response_text": { + "type": "string", + "nullable": true, + "description": "Health check response text." + }, + "health_check_interval": { + "type": "integer", + "description": "Health check interval in seconds." + }, + "health_check_timeout": { + "type": "integer", + "description": "Health check timeout in seconds." + }, + "health_check_retries": { + "type": "integer", + "description": "Health check retries count." + }, + "health_check_start_period": { + "type": "integer", + "description": "Health check start period in seconds." + }, + "limits_memory": { + "type": "string", + "description": "Memory limit." + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit." + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness." + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation." + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit." + }, + "limits_cpuset": { + "type": "string", + "nullable": true, + "description": "CPU set." + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares." + }, + "custom_labels": { + "type": "string", + "description": "Custom labels." + }, + "custom_docker_run_options": { + "type": "string", + "description": "Custom docker run options." + }, + "post_deployment_command": { + "type": "string", + "description": "Post deployment command." + }, + "post_deployment_command_container": { + "type": "string", + "description": "Post deployment command container." + }, + "pre_deployment_command": { + "type": "string", + "description": "Pre deployment command." + }, + "pre_deployment_command_container": { + "type": "string", + "description": "Pre deployment command container." + }, + "manual_webhook_secret_github": { + "type": "string", + "description": "Manual webhook secret for Github." + }, + "manual_webhook_secret_gitlab": { + "type": "string", + "description": "Manual webhook secret for Gitlab." + }, + "manual_webhook_secret_bitbucket": { + "type": "string", + "description": "Manual webhook secret for Bitbucket." + }, + "manual_webhook_secret_gitea": { + "type": "string", + "description": "Manual webhook secret for Gitea." + }, + "redirect": { + "type": "string", + "nullable": true, + "description": "How to set redirect with Traefik \/ Caddy. www<->non-www.", + "enum": [ + "www", + "non-www", + "both" + ] + }, + "instant_deploy": { + "type": "boolean", + "description": "The flag to indicate if the application should be deployed instantly." + }, + "use_build_server": { + "type": "boolean", + "nullable": true, + "description": "Use build server." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Application created successfully." + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/dockerimage": { + "post": { + "tags": [ + "Applications" + ], + "summary": "Create (Docker Image)", + "description": "Create new application based on a prebuilt docker image", + "operationId": "create-dockerimage-application", + "requestBody": { + "description": "Application object that needs to be created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "project_uuid", + "server_uuid", + "environment_name", + "docker_registry_image_name", + "ports_exposes" + ], + "properties": { + "project_uuid": { + "type": "string", + "description": "The project UUID." + }, + "server_uuid": { + "type": "string", + "description": "The server UUID." + }, + "environment_name": { + "type": "string", + "description": "The environment name." + }, + "docker_registry_image_name": { + "type": "string", + "description": "The docker registry image name." + }, + "docker_registry_image_tag": { + "type": "string", + "description": "The docker registry image tag." + }, + "ports_exposes": { + "type": "string", + "description": "The ports to expose." + }, + "destination_uuid": { + "type": "string", + "description": "The destination UUID." + }, + "name": { + "type": "string", + "description": "The application name." + }, + "description": { + "type": "string", + "description": "The application description." + }, + "domains": { + "type": "string", + "description": "The application domains." + }, + "ports_mappings": { + "type": "string", + "description": "The ports mappings." + }, + "health_check_enabled": { + "type": "boolean", + "description": "Health check enabled." + }, + "health_check_path": { + "type": "string", + "description": "Health check path." + }, + "health_check_port": { + "type": "string", + "nullable": true, + "description": "Health check port." + }, + "health_check_host": { + "type": "string", + "nullable": true, + "description": "Health check host." + }, + "health_check_method": { + "type": "string", + "description": "Health check method." + }, + "health_check_return_code": { + "type": "integer", + "description": "Health check return code." + }, + "health_check_scheme": { + "type": "string", + "description": "Health check scheme." + }, + "health_check_response_text": { + "type": "string", + "nullable": true, + "description": "Health check response text." + }, + "health_check_interval": { + "type": "integer", + "description": "Health check interval in seconds." + }, + "health_check_timeout": { + "type": "integer", + "description": "Health check timeout in seconds." + }, + "health_check_retries": { + "type": "integer", + "description": "Health check retries count." + }, + "health_check_start_period": { + "type": "integer", + "description": "Health check start period in seconds." + }, + "limits_memory": { + "type": "string", + "description": "Memory limit." + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit." + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness." + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation." + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit." + }, + "limits_cpuset": { + "type": "string", + "nullable": true, + "description": "CPU set." + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares." + }, + "custom_labels": { + "type": "string", + "description": "Custom labels." + }, + "custom_docker_run_options": { + "type": "string", + "description": "Custom docker run options." + }, + "post_deployment_command": { + "type": "string", + "description": "Post deployment command." + }, + "post_deployment_command_container": { + "type": "string", + "description": "Post deployment command container." + }, + "pre_deployment_command": { + "type": "string", + "description": "Pre deployment command." + }, + "pre_deployment_command_container": { + "type": "string", + "description": "Pre deployment command container." + }, + "manual_webhook_secret_github": { + "type": "string", + "description": "Manual webhook secret for Github." + }, + "manual_webhook_secret_gitlab": { + "type": "string", + "description": "Manual webhook secret for Gitlab." + }, + "manual_webhook_secret_bitbucket": { + "type": "string", + "description": "Manual webhook secret for Bitbucket." + }, + "manual_webhook_secret_gitea": { + "type": "string", + "description": "Manual webhook secret for Gitea." + }, + "redirect": { + "type": "string", + "nullable": true, + "description": "How to set redirect with Traefik \/ Caddy. www<->non-www.", + "enum": [ + "www", + "non-www", + "both" + ] + }, + "instant_deploy": { + "type": "boolean", + "description": "The flag to indicate if the application should be deployed instantly." + }, + "use_build_server": { + "type": "boolean", + "nullable": true, + "description": "Use build server." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Application created successfully." + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/dockercompose": { + "post": { + "tags": [ + "Applications" + ], + "summary": "Create (Docker Compose)", + "description": "Create new application based on a docker-compose file.", + "operationId": "create-dockercompose-application", + "requestBody": { + "description": "Application object that needs to be created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "project_uuid", + "server_uuid", + "environment_name", + "docker_compose_raw" + ], + "properties": { + "project_uuid": { + "type": "string", + "description": "The project UUID." + }, + "server_uuid": { + "type": "string", + "description": "The server UUID." + }, + "environment_name": { + "type": "string", + "description": "The environment name." + }, + "docker_compose_raw": { + "type": "string", + "description": "The Docker Compose raw content." + }, + "destination_uuid": { + "type": "string", + "description": "The destination UUID if the server has more than one destinations." + }, + "name": { + "type": "string", + "description": "The application name." + }, + "description": { + "type": "string", + "description": "The application description." + }, + "instant_deploy": { + "type": "boolean", + "description": "The flag to indicate if the application should be deployed instantly." + }, + "use_build_server": { + "type": "boolean", + "nullable": true, + "description": "Use build server." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Application created successfully." + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/{uuid}": { + "get": { + "tags": [ + "Applications" + ], + "summary": "Get", + "description": "Get application by UUID.", + "operationId": "get-application-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Get application by UUID.", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/Application" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Applications" + ], + "summary": "Delete", + "description": "Delete application by UUID.", + "operationId": "delete-application-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "delete_configurations", + "in": "query", + "description": "Delete configurations.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "delete_volumes", + "in": "query", + "description": "Delete volumes.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "docker_cleanup", + "in": "query", + "description": "Run docker cleanup.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "delete_connected_networks", + "in": "query", + "description": "Delete connected networks.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Application deleted.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Application deleted." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Applications" + ], + "summary": "Update", + "description": "Update application by UUID.", + "operationId": "update-application-by-uuid", + "requestBody": { + "description": "Application updated.", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "project_uuid": { + "type": "string", + "description": "The project UUID." + }, + "server_uuid": { + "type": "string", + "description": "The server UUID." + }, + "environment_name": { + "type": "string", + "description": "The environment name." + }, + "github_app_uuid": { + "type": "string", + "description": "The Github App UUID." + }, + "git_repository": { + "type": "string", + "description": "The git repository URL." + }, + "git_branch": { + "type": "string", + "description": "The git branch." + }, + "ports_exposes": { + "type": "string", + "description": "The ports to expose." + }, + "destination_uuid": { + "type": "string", + "description": "The destination UUID." + }, + "build_pack": { + "type": "string", + "enum": [ + "nixpacks", + "static", + "dockerfile", + "dockercompose" + ], + "description": "The build pack type." + }, + "name": { + "type": "string", + "description": "The application name." + }, + "description": { + "type": "string", + "description": "The application description." + }, + "domains": { + "type": "string", + "description": "The application domains." + }, + "git_commit_sha": { + "type": "string", + "description": "The git commit SHA." + }, + "docker_registry_image_name": { + "type": "string", + "description": "The docker registry image name." + }, + "docker_registry_image_tag": { + "type": "string", + "description": "The docker registry image tag." + }, + "is_static": { + "type": "boolean", + "description": "The flag to indicate if the application is static." + }, + "install_command": { + "type": "string", + "description": "The install command." + }, + "build_command": { + "type": "string", + "description": "The build command." + }, + "start_command": { + "type": "string", + "description": "The start command." + }, + "ports_mappings": { + "type": "string", + "description": "The ports mappings." + }, + "base_directory": { + "type": "string", + "description": "The base directory for all commands." + }, + "publish_directory": { + "type": "string", + "description": "The publish directory." + }, + "health_check_enabled": { + "type": "boolean", + "description": "Health check enabled." + }, + "health_check_path": { + "type": "string", + "description": "Health check path." + }, + "health_check_port": { + "type": "string", + "nullable": true, + "description": "Health check port." + }, + "health_check_host": { + "type": "string", + "nullable": true, + "description": "Health check host." + }, + "health_check_method": { + "type": "string", + "description": "Health check method." + }, + "health_check_return_code": { + "type": "integer", + "description": "Health check return code." + }, + "health_check_scheme": { + "type": "string", + "description": "Health check scheme." + }, + "health_check_response_text": { + "type": "string", + "nullable": true, + "description": "Health check response text." + }, + "health_check_interval": { + "type": "integer", + "description": "Health check interval in seconds." + }, + "health_check_timeout": { + "type": "integer", + "description": "Health check timeout in seconds." + }, + "health_check_retries": { + "type": "integer", + "description": "Health check retries count." + }, + "health_check_start_period": { + "type": "integer", + "description": "Health check start period in seconds." + }, + "limits_memory": { + "type": "string", + "description": "Memory limit." + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit." + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness." + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation." + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit." + }, + "limits_cpuset": { + "type": "string", + "nullable": true, + "description": "CPU set." + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares." + }, + "custom_labels": { + "type": "string", + "description": "Custom labels." + }, + "custom_docker_run_options": { + "type": "string", + "description": "Custom docker run options." + }, + "post_deployment_command": { + "type": "string", + "description": "Post deployment command." + }, + "post_deployment_command_container": { + "type": "string", + "description": "Post deployment command container." + }, + "pre_deployment_command": { + "type": "string", + "description": "Pre deployment command." + }, + "pre_deployment_command_container": { + "type": "string", + "description": "Pre deployment command container." + }, + "manual_webhook_secret_github": { + "type": "string", + "description": "Manual webhook secret for Github." + }, + "manual_webhook_secret_gitlab": { + "type": "string", + "description": "Manual webhook secret for Gitlab." + }, + "manual_webhook_secret_bitbucket": { + "type": "string", + "description": "Manual webhook secret for Bitbucket." + }, + "manual_webhook_secret_gitea": { + "type": "string", + "description": "Manual webhook secret for Gitea." + }, + "redirect": { + "type": "string", + "nullable": true, + "description": "How to set redirect with Traefik \/ Caddy. www<->non-www.", + "enum": [ + "www", + "non-www", + "both" + ] + }, + "instant_deploy": { + "type": "boolean", + "description": "The flag to indicate if the application should be deployed instantly." + }, + "dockerfile": { + "type": "string", + "description": "The Dockerfile content." + }, + "docker_compose_location": { + "type": "string", + "description": "The Docker Compose location." + }, + "docker_compose_raw": { + "type": "string", + "description": "The Docker Compose raw content." + }, + "docker_compose_custom_start_command": { + "type": "string", + "description": "The Docker Compose custom start command." + }, + "docker_compose_custom_build_command": { + "type": "string", + "description": "The Docker Compose custom build command." + }, + "docker_compose_domains": { + "type": "array", + "description": "The Docker Compose domains." + }, + "watch_paths": { + "type": "string", + "description": "The watch paths." + }, + "use_build_server": { + "type": "boolean", + "nullable": true, + "description": "Use build server." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Application updated.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/{uuid}\/envs": { + "get": { + "tags": [ + "Applications" + ], + "summary": "List Envs", + "description": "List all envs by application UUID.", + "operationId": "list-envs-by-application-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "All environment variables by application UUID.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/EnvironmentVariable" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Applications" + ], + "summary": "Create Env", + "description": "Create env by application UUID.", + "operationId": "create-env-by-application-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Env created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "key": { + "type": "string", + "description": "The key of the environment variable." + }, + "value": { + "type": "string", + "description": "The value of the environment variable." + }, + "is_preview": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in preview deployments." + }, + "is_build_time": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in build time." + }, + "is_literal": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is a literal, nothing espaced." + }, + "is_multiline": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is multiline." + }, + "is_shown_once": { + "type": "boolean", + "description": "The flag to indicate if the environment variable's value is shown on the UI." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Environment variable created.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string", + "example": "nc0k04gk8g0cgsk440g0koko" + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Applications" + ], + "summary": "Update Env", + "description": "Update env by application UUID.", + "operationId": "update-env-by-application-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Env updated.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "The key of the environment variable." + }, + "value": { + "type": "string", + "description": "The value of the environment variable." + }, + "is_preview": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in preview deployments." + }, + "is_build_time": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in build time." + }, + "is_literal": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is a literal, nothing espaced." + }, + "is_multiline": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is multiline." + }, + "is_shown_once": { + "type": "boolean", + "description": "The flag to indicate if the environment variable's value is shown on the UI." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Environment variable updated.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Environment variable updated." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/{uuid}\/envs\/bulk": { + "patch": { + "tags": [ + "Applications" + ], + "summary": "Update Envs (Bulk)", + "description": "Update multiple envs by application UUID.", + "operationId": "update-envs-by-application-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Bulk envs updated.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "properties": { + "key": { + "type": "string", + "description": "The key of the environment variable." + }, + "value": { + "type": "string", + "description": "The value of the environment variable." + }, + "is_preview": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in preview deployments." + }, + "is_build_time": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in build time." + }, + "is_literal": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is a literal, nothing espaced." + }, + "is_multiline": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is multiline." + }, + "is_shown_once": { + "type": "boolean", + "description": "The flag to indicate if the environment variable's value is shown on the UI." + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Environment variables updated.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Environment variables updated." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/{uuid}\/envs\/{env_uuid}": { + "delete": { + "tags": [ + "Applications" + ], + "summary": "Delete Env", + "description": "Delete env by UUID.", + "operationId": "delete-env-by-application-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "env_uuid", + "in": "path", + "description": "UUID of the environment variable.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Environment variable deleted.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Environment variable deleted." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/{uuid}\/start": { + "get": { + "tags": [ + "Applications" + ], + "summary": "Start", + "description": "Start application. `Post` request is also accepted.", + "operationId": "start-application-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "force", + "in": "query", + "description": "Force rebuild.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "instant_deploy", + "in": "query", + "description": "Instant deploy (skip queuing).", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Start application.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Deployment request queued.", + "description": "Message." + }, + "deployment_uuid": { + "type": "string", + "example": "doogksw", + "description": "UUID of the deployment." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/{uuid}\/stop": { + "get": { + "tags": [ + "Applications" + ], + "summary": "Stop", + "description": "Stop application. `Post` request is also accepted.", + "operationId": "stop-application-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Stop application.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Application stopping request queued." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/{uuid}\/restart": { + "get": { + "tags": [ + "Applications" + ], + "summary": "Restart", + "description": "Restart application. `Post` request is also accepted.", + "operationId": "restart-application-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Restart application.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Restart request queued." + }, + "deployment_uuid": { + "type": "string", + "example": "doogksw", + "description": "UUID of the deployment." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/applications\/{uuid}\/execute": { + "post": { + "tags": [ + "Applications" + ], + "summary": "Execute Command", + "description": "Execute a command on the application's current container.", + "operationId": "execute-command-application", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Command to execute.", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "command": { + "type": "string", + "description": "Command to execute." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Execute a command on the application's current container.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Command executed." + }, + "response": { + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases": { + "get": { + "tags": [ + "Databases" + ], + "summary": "List", + "description": "List all databases.", + "operationId": "list-databases", + "responses": { + "200": { + "description": "Get all databases", + "content": { + "application\/json": { + "schema": { + "type": "string" + }, + "example": "Content is very complex. Will be implemented later." + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/{uuid}": { + "get": { + "tags": [ + "Databases" + ], + "summary": "Get", + "description": "Get database by UUID.", + "operationId": "get-database-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the database.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Get all databases", + "content": { + "application\/json": { + "schema": { + "type": "string" + }, + "example": "Content is very complex. Will be implemented later." + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Databases" + ], + "summary": "Delete", + "description": "Delete database by UUID.", + "operationId": "delete-database-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the database.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "delete_configurations", + "in": "query", + "description": "Delete configurations.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "delete_volumes", + "in": "query", + "description": "Delete volumes.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "docker_cleanup", + "in": "query", + "description": "Run docker cleanup.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "delete_connected_networks", + "in": "query", + "description": "Delete connected networks.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Database deleted.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Database deleted." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Databases" + ], + "summary": "Update", + "description": "Update database by UUID.", + "operationId": "update-database-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the database.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "postgres_user": { + "type": "string", + "description": "PostgreSQL user" + }, + "postgres_password": { + "type": "string", + "description": "PostgreSQL password" + }, + "postgres_db": { + "type": "string", + "description": "PostgreSQL database" + }, + "postgres_initdb_args": { + "type": "string", + "description": "PostgreSQL initdb args" + }, + "postgres_host_auth_method": { + "type": "string", + "description": "PostgreSQL host auth method" + }, + "postgres_conf": { + "type": "string", + "description": "PostgreSQL conf" + }, + "clickhouse_admin_user": { + "type": "string", + "description": "Clickhouse admin user" + }, + "clickhouse_admin_password": { + "type": "string", + "description": "Clickhouse admin password" + }, + "dragonfly_password": { + "type": "string", + "description": "DragonFly password" + }, + "redis_password": { + "type": "string", + "description": "Redis password" + }, + "redis_conf": { + "type": "string", + "description": "Redis conf" + }, + "keydb_password": { + "type": "string", + "description": "KeyDB password" + }, + "keydb_conf": { + "type": "string", + "description": "KeyDB conf" + }, + "mariadb_conf": { + "type": "string", + "description": "MariaDB conf" + }, + "mariadb_root_password": { + "type": "string", + "description": "MariaDB root password" + }, + "mariadb_user": { + "type": "string", + "description": "MariaDB user" + }, + "mariadb_password": { + "type": "string", + "description": "MariaDB password" + }, + "mariadb_database": { + "type": "string", + "description": "MariaDB database" + }, + "mongo_conf": { + "type": "string", + "description": "Mongo conf" + }, + "mongo_initdb_root_username": { + "type": "string", + "description": "Mongo initdb root username" + }, + "mongo_initdb_root_password": { + "type": "string", + "description": "Mongo initdb root password" + }, + "mongo_initdb_init_database": { + "type": "string", + "description": "Mongo initdb init database" + }, + "mysql_root_password": { + "type": "string", + "description": "MySQL root password" + }, + "mysql_user": { + "type": "string", + "description": "MySQL user" + }, + "mysql_database": { + "type": "string", + "description": "MySQL database" + }, + "mysql_conf": { + "type": "string", + "description": "MySQL conf" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/postgresql": { + "post": { + "tags": [ + "Databases" + ], + "summary": "Create (PostgreSQL)", + "description": "Create a new PostgreSQL database.", + "operationId": "create-database-postgresql", + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name" + ], + "properties": { + "server_uuid": { + "type": "string", + "description": "UUID of the server" + }, + "project_uuid": { + "type": "string", + "description": "UUID of the project" + }, + "environment_name": { + "type": "string", + "description": "Name of the environment" + }, + "postgres_user": { + "type": "string", + "description": "PostgreSQL user" + }, + "postgres_password": { + "type": "string", + "description": "PostgreSQL password" + }, + "postgres_db": { + "type": "string", + "description": "PostgreSQL database" + }, + "postgres_initdb_args": { + "type": "string", + "description": "PostgreSQL initdb args" + }, + "postgres_host_auth_method": { + "type": "string", + "description": "PostgreSQL host auth method" + }, + "postgres_conf": { + "type": "string", + "description": "PostgreSQL conf" + }, + "destination_uuid": { + "type": "string", + "description": "UUID of the destination if the server has multiple destinations" + }, + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "instant_deploy": { + "type": "boolean", + "description": "Instant deploy the database" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/clickhouse": { + "post": { + "tags": [ + "Databases" + ], + "summary": "Create (Clickhouse)", + "description": "Create a new Clickhouse database.", + "operationId": "create-database-clickhouse", + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name" + ], + "properties": { + "server_uuid": { + "type": "string", + "description": "UUID of the server" + }, + "project_uuid": { + "type": "string", + "description": "UUID of the project" + }, + "environment_name": { + "type": "string", + "description": "Name of the environment" + }, + "destination_uuid": { + "type": "string", + "description": "UUID of the destination if the server has multiple destinations" + }, + "clickhouse_admin_user": { + "type": "string", + "description": "Clickhouse admin user" + }, + "clickhouse_admin_password": { + "type": "string", + "description": "Clickhouse admin password" + }, + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "instant_deploy": { + "type": "boolean", + "description": "Instant deploy the database" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/dragonfly": { + "post": { + "tags": [ + "Databases" + ], + "summary": "Create (DragonFly)", + "description": "Create a new DragonFly database.", + "operationId": "create-database-dragonfly", + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name" + ], + "properties": { + "server_uuid": { + "type": "string", + "description": "UUID of the server" + }, + "project_uuid": { + "type": "string", + "description": "UUID of the project" + }, + "environment_name": { + "type": "string", + "description": "Name of the environment" + }, + "destination_uuid": { + "type": "string", + "description": "UUID of the destination if the server has multiple destinations" + }, + "dragonfly_password": { + "type": "string", + "description": "DragonFly password" + }, + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "instant_deploy": { + "type": "boolean", + "description": "Instant deploy the database" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/redis": { + "post": { + "tags": [ + "Databases" + ], + "summary": "Create (Redis)", + "description": "Create a new Redis database.", + "operationId": "create-database-redis", + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name" + ], + "properties": { + "server_uuid": { + "type": "string", + "description": "UUID of the server" + }, + "project_uuid": { + "type": "string", + "description": "UUID of the project" + }, + "environment_name": { + "type": "string", + "description": "Name of the environment" + }, + "destination_uuid": { + "type": "string", + "description": "UUID of the destination if the server has multiple destinations" + }, + "redis_password": { + "type": "string", + "description": "Redis password" + }, + "redis_conf": { + "type": "string", + "description": "Redis conf" + }, + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "instant_deploy": { + "type": "boolean", + "description": "Instant deploy the database" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/keydb": { + "post": { + "tags": [ + "Databases" + ], + "summary": "Create (KeyDB)", + "description": "Create a new KeyDB database.", + "operationId": "create-database-keydb", + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name" + ], + "properties": { + "server_uuid": { + "type": "string", + "description": "UUID of the server" + }, + "project_uuid": { + "type": "string", + "description": "UUID of the project" + }, + "environment_name": { + "type": "string", + "description": "Name of the environment" + }, + "destination_uuid": { + "type": "string", + "description": "UUID of the destination if the server has multiple destinations" + }, + "keydb_password": { + "type": "string", + "description": "KeyDB password" + }, + "keydb_conf": { + "type": "string", + "description": "KeyDB conf" + }, + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "instant_deploy": { + "type": "boolean", + "description": "Instant deploy the database" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/mariadb": { + "post": { + "tags": [ + "Databases" + ], + "summary": "Create (MariaDB)", + "description": "Create a new MariaDB database.", + "operationId": "create-database-mariadb", + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name" + ], + "properties": { + "server_uuid": { + "type": "string", + "description": "UUID of the server" + }, + "project_uuid": { + "type": "string", + "description": "UUID of the project" + }, + "environment_name": { + "type": "string", + "description": "Name of the environment" + }, + "destination_uuid": { + "type": "string", + "description": "UUID of the destination if the server has multiple destinations" + }, + "mariadb_conf": { + "type": "string", + "description": "MariaDB conf" + }, + "mariadb_root_password": { + "type": "string", + "description": "MariaDB root password" + }, + "mariadb_user": { + "type": "string", + "description": "MariaDB user" + }, + "mariadb_password": { + "type": "string", + "description": "MariaDB password" + }, + "mariadb_database": { + "type": "string", + "description": "MariaDB database" + }, + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "instant_deploy": { + "type": "boolean", + "description": "Instant deploy the database" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/mysql": { + "post": { + "tags": [ + "Databases" + ], + "summary": "Create (MySQL)", + "description": "Create a new MySQL database.", + "operationId": "create-database-mysql", + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name" + ], + "properties": { + "server_uuid": { + "type": "string", + "description": "UUID of the server" + }, + "project_uuid": { + "type": "string", + "description": "UUID of the project" + }, + "environment_name": { + "type": "string", + "description": "Name of the environment" + }, + "destination_uuid": { + "type": "string", + "description": "UUID of the destination if the server has multiple destinations" + }, + "mysql_root_password": { + "type": "string", + "description": "MySQL root password" + }, + "mysql_user": { + "type": "string", + "description": "MySQL user" + }, + "mysql_database": { + "type": "string", + "description": "MySQL database" + }, + "mysql_conf": { + "type": "string", + "description": "MySQL conf" + }, + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "instant_deploy": { + "type": "boolean", + "description": "Instant deploy the database" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/mongodb": { + "post": { + "tags": [ + "Databases" + ], + "summary": "Create (MongoDB)", + "description": "Create a new MongoDB database.", + "operationId": "create-database-mongodb", + "requestBody": { + "description": "Database data", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name" + ], + "properties": { + "server_uuid": { + "type": "string", + "description": "UUID of the server" + }, + "project_uuid": { + "type": "string", + "description": "UUID of the project" + }, + "environment_name": { + "type": "string", + "description": "Name of the environment" + }, + "destination_uuid": { + "type": "string", + "description": "UUID of the destination if the server has multiple destinations" + }, + "mongo_conf": { + "type": "string", + "description": "MongoDB conf" + }, + "mongo_initdb_root_username": { + "type": "string", + "description": "MongoDB initdb root username" + }, + "name": { + "type": "string", + "description": "Name of the database" + }, + "description": { + "type": "string", + "description": "Description of the database" + }, + "image": { + "type": "string", + "description": "Docker Image of the database" + }, + "is_public": { + "type": "boolean", + "description": "Is the database public?" + }, + "public_port": { + "type": "integer", + "description": "Public port of the database" + }, + "limits_memory": { + "type": "string", + "description": "Memory limit of the database" + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit of the database" + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness of the database" + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation of the database" + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit of the database" + }, + "limits_cpuset": { + "type": "string", + "description": "CPU set of the database" + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares of the database" + }, + "instant_deploy": { + "type": "boolean", + "description": "Instant deploy the database" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Database updated" + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/{uuid}\/start": { + "get": { + "tags": [ + "Databases" + ], + "summary": "Start", + "description": "Start database. `Post` request is also accepted.", + "operationId": "start-database-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the database.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Start database.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Database starting request queued." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/{uuid}\/stop": { + "get": { + "tags": [ + "Databases" + ], + "summary": "Stop", + "description": "Stop database. `Post` request is also accepted.", + "operationId": "stop-database-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the database.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Stop database.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Database stopping request queued." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/databases\/{uuid}\/restart": { + "get": { + "tags": [ + "Databases" + ], + "summary": "Restart", + "description": "Restart database. `Post` request is also accepted.", + "operationId": "restart-database-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the database.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Restart database.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Database restaring request queued." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/deployments": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "List", + "description": "List currently running deployments", + "operationId": "list-deployments", + "responses": { + "200": { + "description": "Get all currently running deployments.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/ApplicationDeploymentQueue" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/deployments\/{uuid}": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Get", + "description": "Get deployment by UUID.", + "operationId": "get-deployment-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Deployment UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Get deployment by UUID.", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/ApplicationDeploymentQueue" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/deploy": { + "get": { + "tags": [ + "Deployments" + ], + "summary": "Deploy", + "description": "Deploy by tag or uuid. `Post` request also accepted.", + "operationId": "deploy-by-tag-or-uuid", + "parameters": [ + { + "name": "tag", + "in": "query", + "description": "Tag name(s). Comma separated list is also accepted.", + "schema": { + "type": "string" + } + }, + { + "name": "uuid", + "in": "query", + "description": "Resource UUID(s). Comma separated list is also accepted.", + "schema": { + "type": "string" + } + }, + { + "name": "force", + "in": "query", + "description": "Force rebuild (without cache)", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Get deployment(s) UUID's", + "content": { + "application\/json": { + "schema": { + "properties": { + "deployments": { + "type": "array", + "items": { + "properties": { + "message": { + "type": "string" + }, + "resource_uuid": { + "type": "string" + }, + "deployment_uuid": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/version": { + "get": { + "summary": "Version", + "description": "Get Coolify version.", + "operationId": "version", + "responses": { + "200": { + "description": "Returns the version of the application", + "content": { + "application\/json": { + "schema": { + "type": "string" + }, + "example": "v4.0.0" + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/enable": { + "get": { + "summary": "Enable API", + "description": "Enable API (only with root permissions).", + "operationId": "enable-api", + "responses": { + "200": { + "description": "Enable API.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "API enabled." + } + }, + "type": "object" + } + } + } + }, + "403": { + "description": "You are not allowed to enable the API.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "You are not allowed to enable the API." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/disable": { + "get": { + "summary": "Disable API", + "description": "Disable API (only with root permissions).", + "operationId": "disable-api", + "responses": { + "200": { + "description": "Disable API.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "API disabled." + } + }, + "type": "object" + } + } + } + }, + "403": { + "description": "You are not allowed to disable the API.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "You are not allowed to disable the API." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/health": { + "get": { + "summary": "Healthcheck", + "description": "Healthcheck endpoint.", + "operationId": "healthcheck", + "responses": { + "200": { + "description": "Healthcheck endpoint.", + "content": { + "application\/json": { + "schema": { + "type": "string" + }, + "example": "OK" + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + } + } + }, + "\/projects": { + "get": { + "tags": [ + "Projects" + ], + "summary": "List", + "description": "List projects.", + "operationId": "list-projects", + "responses": { + "200": { + "description": "Get all projects.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/Project" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Projects" + ], + "summary": "Create", + "description": "Create Project.", + "operationId": "create-project", + "requestBody": { + "description": "Project created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "name": { + "type": "string", + "description": "The name of the project." + }, + "description": { + "type": "string", + "description": "The description of the project." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Project created.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string", + "example": "og888os", + "description": "The UUID of the project." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/projects\/{uuid}": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Get", + "description": "Get project by UUID.", + "operationId": "get-project-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Project UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Project details", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/Project" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "description": "Project not found." + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Projects" + ], + "summary": "Delete", + "description": "Delete project by UUID.", + "operationId": "delete-project-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the application.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Project deleted.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Project deleted." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Projects" + ], + "summary": "Update", + "description": "Update Project.", + "operationId": "update-project-by-uuid", + "requestBody": { + "description": "Project updated.", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "name": { + "type": "string", + "description": "The name of the project." + }, + "description": { + "type": "string", + "description": "The description of the project." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Project updated.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string", + "example": "og888os" + }, + "name": { + "type": "string", + "example": "Project Name" + }, + "description": { + "type": "string", + "example": "Project Description" + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/projects\/{uuid}\/{environment_name}": { + "get": { + "tags": [ + "Projects" + ], + "summary": "Environment", + "description": "Get environment by name.", + "operationId": "get-environment-by-name", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Project UUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment_name", + "in": "path", + "description": "Environment name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Environment details", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/Environment" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/resources": { + "get": { + "tags": [ + "Resources" + ], + "summary": "List", + "description": "Get all resources.", + "operationId": "list-resources", + "responses": { + "200": { + "description": "Get all resources", + "content": { + "application\/json": { + "schema": { + "type": "string" + }, + "example": "Content is very complex. Will be implemented later." + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/security\/keys": { + "get": { + "tags": [ + "Private Keys" + ], + "summary": "List", + "description": "List all private keys.", + "operationId": "list-private-keys", + "responses": { + "200": { + "description": "Get all private keys.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/PrivateKey" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Private Keys" + ], + "summary": "Create", + "description": "Create a new private key.", + "operationId": "create-private-key", + "requestBody": { + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "private_key" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "private_key": { + "type": "string" + } + }, + "type": "object", + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "The created private key's UUID.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Private Keys" + ], + "summary": "Update", + "description": "Update a private key.", + "operationId": "update-private-key", + "requestBody": { + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "private_key" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "private_key": { + "type": "string" + } + }, + "type": "object", + "additionalProperties": false + } + } + } + }, + "responses": { + "201": { + "description": "The updated private key's UUID.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/security\/keys\/{uuid}": { + "get": { + "tags": [ + "Private Keys" + ], + "summary": "Get", + "description": "Get key by UUID.", + "operationId": "get-private-key-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Private Key UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Get all private keys.", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/PrivateKey" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "description": "Private Key not found." + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Private Keys" + ], + "summary": "Delete", + "description": "Delete a private key.", + "operationId": "delete-private-key-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Private Key UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Private Key deleted.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Private Key deleted." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "description": "Private Key not found." + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/servers": { + "get": { + "tags": [ + "Servers" + ], + "summary": "List", + "description": "List all servers.", + "operationId": "list-servers", + "responses": { + "200": { + "description": "Get all servers.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/Server" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Servers" + ], + "summary": "Create", + "description": "Create Server.", + "operationId": "create-server", + "requestBody": { + "description": "Server created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "name": { + "type": "string", + "example": "My Server", + "description": "The name of the server." + }, + "description": { + "type": "string", + "example": "My Server Description", + "description": "The description of the server." + }, + "ip": { + "type": "string", + "example": "127.0.0.1", + "description": "The IP of the server." + }, + "port": { + "type": "integer", + "example": 22, + "description": "The port of the server." + }, + "user": { + "type": "string", + "example": "root", + "description": "The user of the server." + }, + "private_key_uuid": { + "type": "string", + "example": "og888os", + "description": "The UUID of the private key." + }, + "is_build_server": { + "type": "boolean", + "example": false, + "description": "Is build server." + }, + "instant_validate": { + "type": "boolean", + "example": false, + "description": "Instant validate." + }, + "proxy_type": { + "type": "string", + "enum": [ + "traefik", + "caddy", + "none" + ], + "example": "traefik", + "description": "The proxy type." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Server created.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string", + "example": "og888os", + "description": "The UUID of the server." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/servers\/{uuid}": { + "get": { + "tags": [ + "Servers" + ], + "summary": "Get", + "description": "Get server by UUID.", + "operationId": "get-server-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Server's UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Get server by UUID", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/Server" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Servers" + ], + "summary": "Delete", + "description": "Delete server by UUID.", + "operationId": "delete-server-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the server.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Server deleted.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Server deleted." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Servers" + ], + "summary": "Update", + "description": "Update Server.", + "operationId": "update-server-by-uuid", + "requestBody": { + "description": "Server updated.", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "name": { + "type": "string", + "description": "The name of the server." + }, + "description": { + "type": "string", + "description": "The description of the server." + }, + "ip": { + "type": "string", + "description": "The IP of the server." + }, + "port": { + "type": "integer", + "description": "The port of the server." + }, + "user": { + "type": "string", + "description": "The user of the server." + }, + "private_key_uuid": { + "type": "string", + "description": "The UUID of the private key." + }, + "is_build_server": { + "type": "boolean", + "description": "Is build server." + }, + "instant_validate": { + "type": "boolean", + "description": "Instant validate." + }, + "proxy_type": { + "type": "string", + "enum": [ + "traefik", + "caddy", + "none" + ], + "description": "The proxy type." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Server updated.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/Server" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/servers\/{uuid}\/resources": { + "get": { + "tags": [ + "Servers" + ], + "summary": "Resources", + "description": "Get resources by server.", + "operationId": "get-resources-by-server-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Server's UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Get resources by server", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "integer" + }, + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "type": "object" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/servers\/{uuid}\/domains": { + "get": { + "tags": [ + "Servers" + ], + "summary": "Domains", + "description": "Get domains by server.", + "operationId": "get-domains-by-server-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Server's UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Get domains by server", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "properties": { + "ip": { + "type": "string" + }, + "domains": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "type": "object" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/servers\/{uuid}\/validate": { + "get": { + "tags": [ + "Servers" + ], + "summary": "Validate", + "description": "Validate server by UUID.", + "operationId": "validate-server-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Server UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Server validation started.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Validation started." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/services": { + "get": { + "tags": [ + "Services" + ], + "summary": "List", + "description": "List all services.", + "operationId": "list-services", + "responses": { + "200": { + "description": "Get all services", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/Service" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Services" + ], + "summary": "Create", + "description": "Create a one-click service", + "operationId": "create-service", + "requestBody": { + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "server_uuid", + "project_uuid", + "environment_name", + "type" + ], + "properties": { + "type": { + "description": "The one-click service type", + "type": "string", + "enum": [ + "activepieces", + "appsmith", + "appwrite", + "authentik", + "babybuddy", + "budge", + "changedetection", + "chatwoot", + "classicpress-with-mariadb", + "classicpress-with-mysql", + "classicpress-without-database", + "cloudflared", + "code-server", + "dashboard", + "directus", + "directus-with-postgresql", + "docker-registry", + "docuseal", + "docuseal-with-postgres", + "dokuwiki", + "duplicati", + "emby", + "embystat", + "fider", + "filebrowser", + "firefly", + "formbricks", + "ghost", + "gitea", + "gitea-with-mariadb", + "gitea-with-mysql", + "gitea-with-postgresql", + "glance", + "glances", + "glitchtip", + "grafana", + "grafana-with-postgresql", + "grocy", + "heimdall", + "homepage", + "jellyfin", + "kuzzle", + "listmonk", + "logto", + "mediawiki", + "meilisearch", + "metabase", + "metube", + "minio", + "moodle", + "n8n", + "n8n-with-postgresql", + "next-image-transformation", + "nextcloud", + "nocodb", + "odoo", + "openblocks", + "pairdrop", + "penpot", + "phpmyadmin", + "pocketbase", + "posthog", + "reactive-resume", + "rocketchat", + "shlink", + "slash", + "snapdrop", + "statusnook", + "stirling-pdf", + "supabase", + "syncthing", + "tolgee", + "trigger", + "trigger-with-external-database", + "twenty", + "umami", + "unleash-with-postgresql", + "unleash-without-database", + "uptime-kuma", + "vaultwarden", + "vikunja", + "weblate", + "whoogle", + "wordpress-with-mariadb", + "wordpress-with-mysql", + "wordpress-without-database" + ] + }, + "name": { + "type": "string", + "maxLength": 255, + "description": "Name of the service." + }, + "description": { + "type": "string", + "nullable": true, + "description": "Description of the service." + }, + "project_uuid": { + "type": "string", + "description": "Project UUID." + }, + "environment_name": { + "type": "string", + "description": "Environment name." + }, + "server_uuid": { + "type": "string", + "description": "Server UUID." + }, + "destination_uuid": { + "type": "string", + "description": "Destination UUID. Required if server has multiple destinations." + }, + "instant_deploy": { + "type": "boolean", + "default": false, + "description": "Start the service immediately after creation." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Create a service.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string", + "description": "Service UUID." + }, + "domains": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Service domains." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/services\/{uuid}": { + "get": { + "tags": [ + "Services" + ], + "summary": "Get", + "description": "Get service by UUID.", + "operationId": "get-service-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Service UUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Get a service by UUID.", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/Service" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": [ + "Services" + ], + "summary": "Delete", + "description": "Delete service by UUID.", + "operationId": "delete-service-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "Service UUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "delete_configurations", + "in": "query", + "description": "Delete configurations.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "delete_volumes", + "in": "query", + "description": "Delete volumes.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "docker_cleanup", + "in": "query", + "description": "Run docker cleanup.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "delete_connected_networks", + "in": "query", + "description": "Delete connected networks.", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Delete a service by UUID", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Service deletion request queued." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/services\/{uuid}\/envs": { + "get": { + "tags": [ + "Services" + ], + "summary": "List Envs", + "description": "List all envs by service UUID.", + "operationId": "list-envs-by-service-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the service.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "All environment variables by service UUID.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/EnvironmentVariable" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": [ + "Services" + ], + "summary": "Create Env", + "description": "Create env by service UUID.", + "operationId": "create-env-by-service-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the service.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Env created.", + "required": true, + "content": { + "application\/json": { + "schema": { + "properties": { + "key": { + "type": "string", + "description": "The key of the environment variable." + }, + "value": { + "type": "string", + "description": "The value of the environment variable." + }, + "is_preview": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in preview deployments." + }, + "is_build_time": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in build time." + }, + "is_literal": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is a literal, nothing espaced." + }, + "is_multiline": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is multiline." + }, + "is_shown_once": { + "type": "boolean", + "description": "The flag to indicate if the environment variable's value is shown on the UI." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Environment variable created.", + "content": { + "application\/json": { + "schema": { + "properties": { + "uuid": { + "type": "string", + "example": "nc0k04gk8g0cgsk440g0koko" + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "patch": { + "tags": [ + "Services" + ], + "summary": "Update Env", + "description": "Update env by service UUID.", + "operationId": "update-env-by-service-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the service.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Env updated.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string", + "description": "The key of the environment variable." + }, + "value": { + "type": "string", + "description": "The value of the environment variable." + }, + "is_preview": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in preview deployments." + }, + "is_build_time": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in build time." + }, + "is_literal": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is a literal, nothing espaced." + }, + "is_multiline": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is multiline." + }, + "is_shown_once": { + "type": "boolean", + "description": "The flag to indicate if the environment variable's value is shown on the UI." + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Environment variable updated.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Environment variable updated." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/services\/{uuid}\/envs\/bulk": { + "patch": { + "tags": [ + "Services" + ], + "summary": "Update Envs (Bulk)", + "description": "Update multiple envs by service UUID.", + "operationId": "update-envs-by-service-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the service.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Bulk envs updated.", + "required": true, + "content": { + "application\/json": { + "schema": { + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "properties": { + "key": { + "type": "string", + "description": "The key of the environment variable." + }, + "value": { + "type": "string", + "description": "The value of the environment variable." + }, + "is_preview": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in preview deployments." + }, + "is_build_time": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is used in build time." + }, + "is_literal": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is a literal, nothing espaced." + }, + "is_multiline": { + "type": "boolean", + "description": "The flag to indicate if the environment variable is multiline." + }, + "is_shown_once": { + "type": "boolean", + "description": "The flag to indicate if the environment variable's value is shown on the UI." + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Environment variables updated.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Environment variables updated." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/services\/{uuid}\/envs\/{env_uuid}": { + "delete": { + "tags": [ + "Services" + ], + "summary": "Delete Env", + "description": "Delete env by UUID.", + "operationId": "delete-env-by-service-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the service.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "env_uuid", + "in": "path", + "description": "UUID of the environment variable.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Environment variable deleted.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Environment variable deleted." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/services\/{uuid}\/start": { + "get": { + "tags": [ + "Services" + ], + "summary": "Start", + "description": "Start service. `Post` request is also accepted.", + "operationId": "start-service-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the service.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Start service.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Service starting request queued." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/services\/{uuid}\/stop": { + "get": { + "tags": [ + "Services" + ], + "summary": "Stop", + "description": "Stop service. `Post` request is also accepted.", + "operationId": "stop-service-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the service.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Stop service.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Service stopping request queued." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/services\/{uuid}\/restart": { + "get": { + "tags": [ + "Services" + ], + "summary": "Restart", + "description": "Restart service. `Post` request is also accepted.", + "operationId": "restart-service-by-uuid", + "parameters": [ + { + "name": "uuid", + "in": "path", + "description": "UUID of the service.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Restart service.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Service restaring request queued." + } + }, + "type": "object" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/teams": { + "get": { + "tags": [ + "Teams" + ], + "summary": "List", + "description": "Get all teams.", + "operationId": "list-teams", + "responses": { + "200": { + "description": "List of teams.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/Team" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/teams\/{id}": { + "get": { + "tags": [ + "Teams" + ], + "summary": "Get", + "description": "Get team by TeamId.", + "operationId": "get-team-by-id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "List of teams.", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/Team" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/teams\/{id}\/members": { + "get": { + "tags": [ + "Teams" + ], + "summary": "Members", + "description": "Get members by TeamId.", + "operationId": "get-members-by-team-id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "List of members.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/User" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + }, + "404": { + "$ref": "#\/components\/responses\/404" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/teams\/current": { + "get": { + "tags": [ + "Teams" + ], + "summary": "Authenticated Team", + "description": "Get currently authenticated team.", + "operationId": "get-current-team", + "responses": { + "200": { + "description": "Current Team.", + "content": { + "application\/json": { + "schema": { + "$ref": "#\/components\/schemas\/Team" + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "\/teams\/current\/members": { + "get": { + "tags": [ + "Teams" + ], + "summary": "Authenticated Team Members", + "description": "Get currently authenticated team members.", + "operationId": "get-current-team-members", + "responses": { + "200": { + "description": "Currently authenticated team members.", + "content": { + "application\/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/User" + } + } + } + } + }, + "401": { + "$ref": "#\/components\/responses\/401" + }, + "400": { + "$ref": "#\/components\/responses\/400" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + } + }, + "components": { + "schemas": { + "Application": { + "description": "Application model", + "properties": { + "id": { + "type": "integer", + "description": "The application identifier in the database." + }, + "description": { + "type": "string", + "nullable": true, + "description": "The application description." + }, + "repository_project_id": { + "type": "integer", + "nullable": true, + "description": "The repository project identifier." + }, + "uuid": { + "type": "string", + "description": "The application UUID." + }, + "name": { + "type": "string", + "description": "The application name." + }, + "fqdn": { + "type": "string", + "nullable": true, + "description": "The application domains." + }, + "config_hash": { + "type": "string", + "description": "Configuration hash." + }, + "git_repository": { + "type": "string", + "description": "Git repository URL." + }, + "git_branch": { + "type": "string", + "description": "Git branch." + }, + "git_commit_sha": { + "type": "string", + "description": "Git commit SHA." + }, + "git_full_url": { + "type": "string", + "nullable": true, + "description": "Git full URL." + }, + "docker_registry_image_name": { + "type": "string", + "nullable": true, + "description": "Docker registry image name." + }, + "docker_registry_image_tag": { + "type": "string", + "nullable": true, + "description": "Docker registry image tag." + }, + "build_pack": { + "type": "string", + "description": "Build pack.", + "enum": [ + "nixpacks", + "static", + "dockerfile", + "dockercompose" + ] + }, + "static_image": { + "type": "string", + "description": "Static image used when static site is deployed." + }, + "install_command": { + "type": "string", + "description": "Install command." + }, + "build_command": { + "type": "string", + "description": "Build command." + }, + "start_command": { + "type": "string", + "description": "Start command." + }, + "ports_exposes": { + "type": "string", + "description": "Ports exposes." + }, + "ports_mappings": { + "type": "string", + "nullable": true, + "description": "Ports mappings." + }, + "base_directory": { + "type": "string", + "description": "Base directory for all commands." + }, + "publish_directory": { + "type": "string", + "description": "Publish directory." + }, + "health_check_enabled": { + "type": "boolean", + "description": "Health check enabled." + }, + "health_check_path": { + "type": "string", + "description": "Health check path." + }, + "health_check_port": { + "type": "string", + "nullable": true, + "description": "Health check port." + }, + "health_check_host": { + "type": "string", + "nullable": true, + "description": "Health check host." + }, + "health_check_method": { + "type": "string", + "description": "Health check method." + }, + "health_check_return_code": { + "type": "integer", + "description": "Health check return code." + }, + "health_check_scheme": { + "type": "string", + "description": "Health check scheme." + }, + "health_check_response_text": { + "type": "string", + "nullable": true, + "description": "Health check response text." + }, + "health_check_interval": { + "type": "integer", + "description": "Health check interval in seconds." + }, + "health_check_timeout": { + "type": "integer", + "description": "Health check timeout in seconds." + }, + "health_check_retries": { + "type": "integer", + "description": "Health check retries count." + }, + "health_check_start_period": { + "type": "integer", + "description": "Health check start period in seconds." + }, + "limits_memory": { + "type": "string", + "description": "Memory limit." + }, + "limits_memory_swap": { + "type": "string", + "description": "Memory swap limit." + }, + "limits_memory_swappiness": { + "type": "integer", + "description": "Memory swappiness." + }, + "limits_memory_reservation": { + "type": "string", + "description": "Memory reservation." + }, + "limits_cpus": { + "type": "string", + "description": "CPU limit." + }, + "limits_cpuset": { + "type": "string", + "nullable": true, + "description": "CPU set." + }, + "limits_cpu_shares": { + "type": "integer", + "description": "CPU shares." + }, + "status": { + "type": "string", + "description": "Application status." + }, + "preview_url_template": { + "type": "string", + "description": "Preview URL template." + }, + "destination_type": { + "type": "string", + "description": "Destination type." + }, + "destination_id": { + "type": "integer", + "description": "Destination identifier." + }, + "source_id": { + "type": "integer", + "nullable": true, + "description": "Source identifier." + }, + "private_key_id": { + "type": "integer", + "nullable": true, + "description": "Private key identifier." + }, + "environment_id": { + "type": "integer", + "description": "Environment identifier." + }, + "dockerfile": { + "type": "string", + "nullable": true, + "description": "Dockerfile content. Used for dockerfile build pack." + }, + "dockerfile_location": { + "type": "string", + "description": "Dockerfile location." + }, + "custom_labels": { + "type": "string", + "nullable": true, + "description": "Custom labels." + }, + "dockerfile_target_build": { + "type": "string", + "nullable": true, + "description": "Dockerfile target build." + }, + "manual_webhook_secret_github": { + "type": "string", + "nullable": true, + "description": "Manual webhook secret for GitHub." + }, + "manual_webhook_secret_gitlab": { + "type": "string", + "nullable": true, + "description": "Manual webhook secret for GitLab." + }, + "manual_webhook_secret_bitbucket": { + "type": "string", + "nullable": true, + "description": "Manual webhook secret for Bitbucket." + }, + "manual_webhook_secret_gitea": { + "type": "string", + "nullable": true, + "description": "Manual webhook secret for Gitea." + }, + "docker_compose_location": { + "type": "string", + "description": "Docker compose location." + }, + "docker_compose": { + "type": "string", + "nullable": true, + "description": "Docker compose content. Used for docker compose build pack." + }, + "docker_compose_raw": { + "type": "string", + "nullable": true, + "description": "Docker compose raw content." + }, + "docker_compose_domains": { + "type": "string", + "nullable": true, + "description": "Docker compose domains." + }, + "docker_compose_custom_start_command": { + "type": "string", + "nullable": true, + "description": "Docker compose custom start command." + }, + "docker_compose_custom_build_command": { + "type": "string", + "nullable": true, + "description": "Docker compose custom build command." + }, + "swarm_replicas": { + "type": "integer", + "nullable": true, + "description": "Swarm replicas. Only used for swarm deployments." + }, + "swarm_placement_constraints": { + "type": "string", + "nullable": true, + "description": "Swarm placement constraints. Only used for swarm deployments." + }, + "custom_docker_run_options": { + "type": "string", + "nullable": true, + "description": "Custom docker run options." + }, + "post_deployment_command": { + "type": "string", + "nullable": true, + "description": "Post deployment command." + }, + "post_deployment_command_container": { + "type": "string", + "nullable": true, + "description": "Post deployment command container." + }, + "pre_deployment_command": { + "type": "string", + "nullable": true, + "description": "Pre deployment command." + }, + "pre_deployment_command_container": { + "type": "string", + "nullable": true, + "description": "Pre deployment command container." + }, + "watch_paths": { + "type": "string", + "nullable": true, + "description": "Watch paths." + }, + "custom_healthcheck_found": { + "type": "boolean", + "description": "Custom healthcheck found." + }, + "redirect": { + "type": "string", + "nullable": true, + "description": "How to set redirect with Traefik \/ Caddy. www<->non-www.", + "enum": [ + "www", + "non-www", + "both" + ] + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time when the application was created." + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The date and time when the application was last updated." + }, + "deleted_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "The date and time when the application was deleted." + }, + "compose_parsing_version": { + "type": "string", + "description": "How Coolify parse the compose file." + }, + "custom_nginx_configuration": { + "type": "string", + "nullable": true, + "description": "Custom Nginx configuration base64 encoded." + } + }, + "type": "object" + }, + "ApplicationDeploymentQueue": { + "description": "Project model", + "properties": { + "id": { + "type": "integer" + }, + "application_id": { + "type": "string" + }, + "deployment_uuid": { + "type": "string" + }, + "pull_request_id": { + "type": "integer" + }, + "force_rebuild": { + "type": "boolean" + }, + "commit": { + "type": "string" + }, + "status": { + "type": "string" + }, + "is_webhook": { + "type": "boolean" + }, + "is_api": { + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "logs": { + "type": "string" + }, + "current_process_id": { + "type": "string" + }, + "restart_only": { + "type": "boolean" + }, + "git_type": { + "type": "string" + }, + "server_id": { + "type": "integer" + }, + "application_name": { + "type": "string" + }, + "server_name": { + "type": "string" + }, + "deployment_url": { + "type": "string" + }, + "destination_id": { + "type": "string" + }, + "only_this_server": { + "type": "boolean" + }, + "rollback": { + "type": "boolean" + }, + "commit_message": { + "type": "string" + } + }, + "type": "object" + }, + "Environment": { + "description": "Environment model", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "project_id": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "type": "object" + }, + "EnvironmentVariable": { + "description": "Environment Variable model", + "properties": { + "id": { + "type": "integer" + }, + "uuid": { + "type": "string" + }, + "application_id": { + "type": "integer" + }, + "service_id": { + "type": "integer" + }, + "database_id": { + "type": "integer" + }, + "is_build_time": { + "type": "boolean" + }, + "is_literal": { + "type": "boolean" + }, + "is_multiline": { + "type": "boolean" + }, + "is_preview": { + "type": "boolean" + }, + "is_shared": { + "type": "boolean" + }, + "is_shown_once": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "real_value": { + "type": "string" + }, + "version": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "type": "object" + }, + "PrivateKey": { + "description": "Private Key model", + "properties": { + "id": { + "type": "integer" + }, + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "private_key": { + "type": "string", + "format": "private-key" + }, + "is_git_related": { + "type": "boolean" + }, + "team_id": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "type": "object" + }, + "Project": { + "description": "Project model", + "properties": { + "id": { + "type": "integer" + }, + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "environments": { + "description": "The environments of the project.", + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/Environment" + } + } + }, + "type": "object" + }, + "Server": { + "description": "Server model", + "properties": { + "id": { + "type": "integer", + "description": "The server ID." + }, + "uuid": { + "type": "string", + "description": "The server UUID." + }, + "name": { + "type": "string", + "description": "The server name." + }, + "description": { + "type": "string", + "description": "The server description." + }, + "ip": { + "type": "string", + "description": "The IP address." + }, + "user": { + "type": "string", + "description": "The user." + }, + "port": { + "type": "integer", + "description": "The port number." + }, + "proxy": { + "type": "object", + "description": "The proxy configuration." + }, + "proxy_type": { + "type": "string", + "enum": [ + "traefik", + "caddy", + "none" + ], + "description": "The proxy type." + }, + "high_disk_usage_notification_sent": { + "type": "boolean", + "description": "The flag to indicate if the high disk usage notification has been sent." + }, + "unreachable_notification_sent": { + "type": "boolean", + "description": "The flag to indicate if the unreachable notification has been sent." + }, + "unreachable_count": { + "type": "integer", + "description": "The unreachable count for your server." + }, + "validation_logs": { + "type": "string", + "description": "The validation logs." + }, + "log_drain_notification_sent": { + "type": "boolean", + "description": "The flag to indicate if the log drain notification has been sent." + }, + "swarm_cluster": { + "type": "string", + "description": "The swarm cluster configuration." + }, + "delete_unused_volumes": { + "type": "boolean", + "description": "The flag to indicate if the unused volumes should be deleted." + }, + "delete_unused_networks": { + "type": "boolean", + "description": "The flag to indicate if the unused networks should be deleted." + } + }, + "type": "object" + }, + "ServerSetting": { + "description": "Server Settings model", + "properties": { + "id": { + "type": "integer" + }, + "concurrent_builds": { + "type": "integer" + }, + "dynamic_timeout": { + "type": "integer" + }, + "force_disabled": { + "type": "boolean" + }, + "force_server_cleanup": { + "type": "boolean" + }, + "is_build_server": { + "type": "boolean" + }, + "is_cloudflare_tunnel": { + "type": "boolean" + }, + "is_jump_server": { + "type": "boolean" + }, + "is_logdrain_axiom_enabled": { + "type": "boolean" + }, + "is_logdrain_custom_enabled": { + "type": "boolean" + }, + "is_logdrain_highlight_enabled": { + "type": "boolean" + }, + "is_logdrain_newrelic_enabled": { + "type": "boolean" + }, + "is_metrics_enabled": { + "type": "boolean" + }, + "is_reachable": { + "type": "boolean" + }, + "is_sentinel_enabled": { + "type": "boolean" + }, + "is_swarm_manager": { + "type": "boolean" + }, + "is_swarm_worker": { + "type": "boolean" + }, + "is_usable": { + "type": "boolean" + }, + "logdrain_axiom_api_key": { + "type": "string" + }, + "logdrain_axiom_dataset_name": { + "type": "string" + }, + "logdrain_custom_config": { + "type": "string" + }, + "logdrain_custom_config_parser": { + "type": "string" + }, + "logdrain_highlight_project_id": { + "type": "string" + }, + "logdrain_newrelic_base_uri": { + "type": "string" + }, + "logdrain_newrelic_license_key": { + "type": "string" + }, + "sentinel_metrics_history_days": { + "type": "integer" + }, + "sentinel_metrics_refresh_rate_seconds": { + "type": "integer" + }, + "sentinel_token": { + "type": "string" + }, + "docker_cleanup_frequency": { + "type": "string" + }, + "docker_cleanup_threshold": { + "type": "integer" + }, + "server_id": { + "type": "integer" + }, + "wildcard_domain": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "type": "object" + }, + "Service": { + "description": "Service model", + "properties": { + "id": { + "type": "integer", + "description": "The unique identifier of the service. Only used for database identification." + }, + "uuid": { + "type": "string", + "description": "The unique identifier of the service." + }, + "name": { + "type": "string", + "description": "The name of the service." + }, + "environment_id": { + "type": "integer", + "description": "The unique identifier of the environment where the service is attached to." + }, + "server_id": { + "type": "integer", + "description": "The unique identifier of the server where the service is running." + }, + "description": { + "type": "string", + "description": "The description of the service." + }, + "docker_compose_raw": { + "type": "string", + "description": "The raw docker-compose.yml file of the service." + }, + "docker_compose": { + "type": "string", + "description": "The docker-compose.yml file that is parsed and modified by Coolify." + }, + "destination_type": { + "type": "string", + "description": "Destination type." + }, + "destination_id": { + "type": "integer", + "description": "The unique identifier of the destination where the service is running." + }, + "connect_to_docker_network": { + "type": "boolean", + "description": "The flag to connect the service to the predefined Docker network." + }, + "is_container_label_escape_enabled": { + "type": "boolean", + "description": "The flag to enable the container label escape." + }, + "is_container_label_readonly_enabled": { + "type": "boolean", + "description": "The flag to enable the container label readonly." + }, + "config_hash": { + "type": "string", + "description": "The hash of the service configuration." + }, + "service_type": { + "type": "string", + "description": "The type of the service." + }, + "created_at": { + "type": "string", + "description": "The date and time when the service was created." + }, + "updated_at": { + "type": "string", + "description": "The date and time when the service was last updated." + }, + "deleted_at": { + "type": "string", + "description": "The date and time when the service was deleted." + } + }, + "type": "object" + }, + "Team": { + "description": "Team model", + "properties": { + "id": { + "type": "integer", + "description": "The unique identifier of the team." + }, + "name": { + "type": "string", + "description": "The name of the team." + }, + "description": { + "type": "string", + "description": "The description of the team." + }, + "personal_team": { + "type": "boolean", + "description": "Whether the team is personal or not." + }, + "created_at": { + "type": "string", + "description": "The date and time the team was created." + }, + "updated_at": { + "type": "string", + "description": "The date and time the team was last updated." + }, + "smtp_enabled": { + "type": "boolean", + "description": "Whether SMTP is enabled or not." + }, + "smtp_from_address": { + "type": "string", + "description": "The email address to send emails from." + }, + "smtp_from_name": { + "type": "string", + "description": "The name to send emails from." + }, + "smtp_recipients": { + "type": "string", + "description": "The email addresses to send emails to." + }, + "smtp_host": { + "type": "string", + "description": "The SMTP host." + }, + "smtp_port": { + "type": "string", + "description": "The SMTP port." + }, + "smtp_encryption": { + "type": "string", + "description": "The SMTP encryption." + }, + "smtp_username": { + "type": "string", + "description": "The SMTP username." + }, + "smtp_password": { + "type": "string", + "description": "The SMTP password." + }, + "smtp_timeout": { + "type": "string", + "description": "The SMTP timeout." + }, + "smtp_notifications_test": { + "type": "boolean", + "description": "Whether to send test notifications via SMTP." + }, + "smtp_notifications_deployments": { + "type": "boolean", + "description": "Whether to send deployment notifications via SMTP." + }, + "smtp_notifications_status_changes": { + "type": "boolean", + "description": "Whether to send status change notifications via SMTP." + }, + "smtp_notifications_scheduled_tasks": { + "type": "boolean", + "description": "Whether to send scheduled task notifications via SMTP." + }, + "smtp_notifications_database_backups": { + "type": "boolean", + "description": "Whether to send database backup notifications via SMTP." + }, + "smtp_notifications_server_disk_usage": { + "type": "boolean", + "description": "Whether to send server disk usage notifications via SMTP." + }, + "discord_enabled": { + "type": "boolean", + "description": "Whether Discord is enabled or not." + }, + "discord_webhook_url": { + "type": "string", + "description": "The Discord webhook URL." + }, + "discord_notifications_test": { + "type": "boolean", + "description": "Whether to send test notifications via Discord." + }, + "discord_notifications_deployments": { + "type": "boolean", + "description": "Whether to send deployment notifications via Discord." + }, + "discord_notifications_status_changes": { + "type": "boolean", + "description": "Whether to send status change notifications via Discord." + }, + "discord_notifications_database_backups": { + "type": "boolean", + "description": "Whether to send database backup notifications via Discord." + }, + "discord_notifications_scheduled_tasks": { + "type": "boolean", + "description": "Whether to send scheduled task notifications via Discord." + }, + "discord_notifications_server_disk_usage": { + "type": "boolean", + "description": "Whether to send server disk usage notifications via Discord." + }, + "show_boarding": { + "type": "boolean", + "description": "Whether to show the boarding screen or not." + }, + "resend_enabled": { + "type": "boolean", + "description": "Whether to enable resending or not." + }, + "resend_api_key": { + "type": "string", + "description": "The resending API key." + }, + "use_instance_email_settings": { + "type": "boolean", + "description": "Whether to use instance email settings or not." + }, + "telegram_enabled": { + "type": "boolean", + "description": "Whether Telegram is enabled or not." + }, + "telegram_token": { + "type": "string", + "description": "The Telegram token." + }, + "telegram_chat_id": { + "type": "string", + "description": "The Telegram chat ID." + }, + "telegram_notifications_test": { + "type": "boolean", + "description": "Whether to send test notifications via Telegram." + }, + "telegram_notifications_deployments": { + "type": "boolean", + "description": "Whether to send deployment notifications via Telegram." + }, + "telegram_notifications_status_changes": { + "type": "boolean", + "description": "Whether to send status change notifications via Telegram." + }, + "telegram_notifications_database_backups": { + "type": "boolean", + "description": "Whether to send database backup notifications via Telegram." + }, + "telegram_notifications_test_message_thread_id": { + "type": "string", + "description": "The Telegram test message thread ID." + }, + "telegram_notifications_deployments_message_thread_id": { + "type": "string", + "description": "The Telegram deployment message thread ID." + }, + "telegram_notifications_status_changes_message_thread_id": { + "type": "string", + "description": "The Telegram status change message thread ID." + }, + "telegram_notifications_database_backups_message_thread_id": { + "type": "string", + "description": "The Telegram database backup message thread ID." + }, + "custom_server_limit": { + "type": "string", + "description": "The custom server limit." + }, + "telegram_notifications_scheduled_tasks": { + "type": "boolean", + "description": "Whether to send scheduled task notifications via Telegram." + }, + "telegram_notifications_scheduled_tasks_thread_id": { + "type": "string", + "description": "The Telegram scheduled task message thread ID." + }, + "members": { + "description": "The members of the team.", + "type": "array", + "items": { + "$ref": "#\/components\/schemas\/User" + } + } + }, + "type": "object" + }, + "User": { + "description": "User model", + "properties": { + "id": { + "type": "integer", + "description": "The user identifier in the database." + }, + "name": { + "type": "string", + "description": "The user name." + }, + "email": { + "type": "string", + "description": "The user email." + }, + "email_verified_at": { + "type": "string", + "description": "The date when the user email was verified." + }, + "created_at": { + "type": "string", + "description": "The date when the user was created." + }, + "updated_at": { + "type": "string", + "description": "The date when the user was updated." + }, + "two_factor_confirmed_at": { + "type": "string", + "description": "The date when the user two factor was confirmed." + }, + "force_password_reset": { + "type": "boolean", + "description": "The flag to force the user to reset the password." + }, + "marketing_emails": { + "type": "boolean", + "description": "The flag to receive marketing emails." + } + }, + "type": "object" + } + }, + "responses": { + "400": { + "description": "Invalid token.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Invalid token." + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "Unauthenticated.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Unauthenticated." + } + }, + "type": "object" + } + } + } + }, + "404": { + "description": "Resource not found.", + "content": { + "application\/json": { + "schema": { + "properties": { + "message": { + "type": "string", + "example": "Resource not found." + } + }, + "type": "object" + } + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "description": "Go to `Keys & Tokens` \/ `API tokens` and create a new token. Use the token as the bearer token.", + "scheme": "bearer" + } + } + }, + "tags": [ + { + "name": "Applications", + "description": "Applications" + }, + { + "name": "Databases", + "description": "Databases" + }, + { + "name": "Deployments", + "description": "Deployments" + }, + { + "name": "Projects", + "description": "Projects" + }, + { + "name": "Resources", + "description": "Resources" + }, + { + "name": "Private Keys", + "description": "Private Keys" + }, + { + "name": "Servers", + "description": "Servers" + }, + { + "name": "Services", + "description": "Services" + }, + { + "name": "Teams", + "description": "Teams" + } + ] +} \ No newline at end of file diff --git a/openapi.yaml b/openapi.yaml index d2616e9c6..c1b93d692 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3311,7 +3311,7 @@ paths: type: string responses: '200': - description: 'Project details' + description: 'Environment details' content: application/json: schema: @@ -3467,9 +3467,7 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/PrivateKey' + $ref: '#/components/schemas/PrivateKey' '401': $ref: '#/components/responses/401' '400': @@ -3579,6 +3577,11 @@ paths: type: boolean example: false description: 'Instant validate.' + proxy_type: + type: string + enum: [traefik, caddy, none] + example: traefik + description: 'The proxy type.' type: object responses: '201': @@ -3699,6 +3702,10 @@ paths: instant_validate: type: boolean description: 'Instant validate.' + proxy_type: + type: string + enum: [traefik, caddy, none] + description: 'The proxy type.' type: object responses: '201': @@ -4759,6 +4766,10 @@ components: compose_parsing_version: type: string description: 'How Coolify parse the compose file.' + custom_nginx_configuration: + type: string + nullable: true + description: 'Custom Nginx configuration base64 encoded.' type: object ApplicationDeploymentQueue: description: 'Project model' @@ -4909,36 +4920,59 @@ components: properties: id: type: integer + description: 'The server ID.' uuid: type: string + description: 'The server UUID.' name: type: string + description: 'The server name.' description: type: string + description: 'The server description.' ip: type: string + description: 'The IP address.' user: type: string + description: 'The user.' port: type: integer + description: 'The port number.' proxy: type: object + description: 'The proxy configuration.' + proxy_type: + type: string + enum: + - traefik + - caddy + - none + description: 'The proxy type.' high_disk_usage_notification_sent: type: boolean + description: 'The flag to indicate if the high disk usage notification has been sent.' unreachable_notification_sent: type: boolean + description: 'The flag to indicate if the unreachable notification has been sent.' unreachable_count: type: integer + description: 'The unreachable count for your server.' validation_logs: type: string + description: 'The validation logs.' log_drain_notification_sent: type: boolean + description: 'The flag to indicate if the log drain notification has been sent.' swarm_cluster: type: string + description: 'The swarm cluster configuration.' delete_unused_volumes: type: boolean + description: 'The flag to indicate if the unused volumes should be deleted.' delete_unused_networks: type: boolean + description: 'The flag to indicate if the unused networks should be deleted.' type: object ServerSetting: description: 'Server Settings model' @@ -5136,6 +5170,9 @@ components: smtp_notifications_database_backups: type: boolean description: 'Whether to send database backup notifications via SMTP.' + smtp_notifications_server_disk_usage: + type: boolean + description: 'Whether to send server disk usage notifications via SMTP.' discord_enabled: type: boolean description: 'Whether Discord is enabled or not.' @@ -5157,6 +5194,9 @@ components: discord_notifications_scheduled_tasks: type: boolean description: 'Whether to send scheduled task notifications via Discord.' + discord_notifications_server_disk_usage: + type: boolean + description: 'Whether to send server disk usage notifications via Discord.' show_boarding: type: boolean description: 'Whether to show the boarding screen or not.' diff --git a/resources/views/errors/500.blade.php b/resources/views/errors/500.blade.php index 4c64d4f8d..f9de400db 100644 --- a/resources/views/errors/500.blade.php +++ b/resources/views/errors/500.blade.php @@ -2,7 +2,7 @@
500
-There has been an error, we are working on it.
@if ($exception->getMessage() !== '') diff --git a/resources/views/livewire/admin/index.blade.php b/resources/views/livewire/admin/index.blade.php index cceb71bb2..06914e1e4 100644 --- a/resources/views/livewire/admin/index.blade.php +++ b/resources/views/livewire/admin/index.blade.php @@ -12,7 +12,7 @@ @if ($foundUsers->count() > 0)This will install the latest Docker Engine on your server, configure a few things to be able
- to run optimal.
Minimum Docker Engine version is: 22
To manually install
+ to run optimal.
Minimum Docker Engine version is: {{ $minDockerVersion }}
To manually install
Docker
Engine, check this
diff --git a/resources/views/livewire/project/resource/index.blade.php b/resources/views/livewire/project/resource/index.blade.php
index 0e16b7266..a618e6db2 100644
--- a/resources/views/livewire/project/resource/index.blade.php
+++ b/resources/views/livewire/project/resource/index.blade.php
@@ -44,17 +44,108 @@