Compare commits

...

6 Commits

Author SHA1 Message Date
Andras Bacsai
884ae0efb0 Merge pull request #1653 from coollabsio/next
v4.0.0-beta.193
2024-01-15 13:03:40 +01:00
Andras Bacsai
8e7040bf7c Update Docker Compose commands to include SOURCE_COMMIT environment variable 2024-01-15 12:59:21 +01:00
Andras Bacsai
059e6a88eb Replace comma with pipe in customLabels 2024-01-15 12:30:49 +01:00
Andras Bacsai
9947158f7e fix gzip compression 2024-01-15 12:12:34 +01:00
Andras Bacsai
61aa9e8766 Merge pull request #1651 from coollabsio/next
v4.0.0-beta.192
2024-01-15 11:53:34 +01:00
Andras Bacsai
75813a289c check domains againts cloudflare ip range 2024-01-15 11:37:26 +01:00
9 changed files with 58 additions and 31 deletions

View File

@@ -477,7 +477,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
);
} else {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
);
}
@@ -521,7 +521,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
);
} else {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true],
);
}
$this->application_deployment_queue->addLogEntry("New container started.");
@@ -756,7 +756,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
} else {
$this->execute_remote_command(
["echo -n 'Starting preview deployment.'"],
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} up -d"), "hidden" => true],
);
}
}
@@ -917,6 +917,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$merged_envs = $this->env_args->merge(collect(data_get($parsed, 'variables', [])));
data_set($parsed, 'variables', $merged_envs->toArray());
$this->nixpacks_plan = json_encode($parsed, JSON_PRETTY_PRINT);
ray($this->nixpacks_plan);
}
}
}
@@ -964,6 +965,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->env_args->put($env->key, $env->value);
}
}
$this->env_args->put('SOURCE_COMMIT', $this->commit);
}
private function generate_compose_file()
@@ -1190,12 +1192,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
}
}
// Add PORT if not exists, use the first port as default
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('PORT'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('PORT'))->isEmpty()) {
$environment_variables->push("PORT={$ports[0]}");
}
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('SOURCE_COMMIT'))->isEmpty()) {
if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('SOURCE_COMMIT'))->isEmpty()) {
if (!is_null($this->commit)) {
$environment_variables->push("SOURCE_COMMIT={$this->commit}");
} else {
$environment_variables->push("SOURCE_COMMIT=unknown");
}
}
return $environment_variables->all();
@@ -1440,11 +1444,11 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
$this->application_deployment_queue->addLogEntry("Pulling latest images from the registry.");
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} build"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} build"), "hidden" => true],
);
} else {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
);
}
$this->application_deployment_queue->addLogEntry("New images built.");
@@ -1456,16 +1460,16 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
$this->application_deployment_queue->addLogEntry("Pulling latest images from the registry.");
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
);
} else {
if ($this->docker_compose_location) {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up --build -d"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up --build -d"), "hidden" => true],
);
} else {
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
);
}
}

View File

@@ -117,7 +117,7 @@ class General extends Component
$this->isConfigurationChanged = $this->application->isConfigurationChanged();
$this->customLabels = $this->application->parseContainerLabels();
if (!$this->customLabels && $this->application->destination->server->proxyType() === 'TRAEFIK_V2') {
$this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
$this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
$this->application->custom_labels = base64_encode($this->customLabels);
$this->application->save();
}
@@ -182,7 +182,7 @@ class General extends Component
}
public function checkLabelUpdates()
{
if (md5($this->application->custom_labels) !== md5(implode(",", generateLabelsApplication($this->application)))) {
if (md5($this->application->custom_labels) !== md5(implode("|", generateLabelsApplication($this->application)))) {
$this->labelsChanged = true;
} else {
$this->labelsChanged = false;
@@ -201,7 +201,7 @@ class General extends Component
}
public function resetDefaultLabels($showToaster = true)
{
$this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
$this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
$this->ports_exposes = $this->application->ports_exposes;
$this->submit($showToaster);
}
@@ -215,7 +215,7 @@ class General extends Component
{
try {
if (!$this->customLabels && $this->application->destination->server->proxyType() === 'TRAEFIK_V2') {
$this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
$this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
$this->application->custom_labels = base64_encode($this->customLabels);
$this->application->save();
}

View File

@@ -1066,7 +1066,7 @@ class Application extends BaseModel
$customLabels = base64_decode($this->custom_labels);
if (mb_detect_encoding($customLabels, 'ASCII', true) === false) {
ray('custom_labels contains non-ascii characters');
$customLabels = str(implode(",", generateLabelsApplication($this, $preview)))->replace(',', "\n");
$customLabels = str(implode("|", generateLabelsApplication($this, $preview)))->replace("|", "\n");
}
$this->custom_labels = base64_encode($customLabels);
$this->save();

View File

@@ -230,7 +230,6 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$https_label = "https-{$loop}-{$uuid}";
$labels->push("traefik.http.middlewares.gzip.compress=true");
$labels->push("traefik.http.routers.{$https_label}.middlewares=gzip");
if ($schema === 'https') {
// Set labels for https
$labels->push("traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
@@ -240,8 +239,10 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$labels->push("traefik.http.services.{$https_label}.loadbalancer.server.port=$port");
}
if ($path !== '/') {
$labels->push("traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix");
$labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}");
$labels->push("traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix,gzip");
} else {
$labels->push("traefik.http.routers.{$https_label}.middlewares=gzip");
}
$labels->push("traefik.http.routers.{$https_label}.tls=true");
@@ -267,8 +268,10 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$labels->push("traefik.http.routers.{$http_label}.service={$http_label}");
}
if ($path !== '/') {
$labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix");
$labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}");
$labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix,gzip");
} else {
$labels->push("traefik.http.routers.{$http_label}.middlewares=gzip");
}
}
} catch (\Throwable $e) {

View File

@@ -1593,6 +1593,9 @@ function getRealtime()
function validate_dns_entry(string $fqdn, Server $server)
{
# https://www.cloudflare.com/ips-v4/#
$cloudflare_ips = collect(['173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22', '141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20', '197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/13', '172.64.0.0/13', '131.0.72.0/22']);
$url = Url::fromString($fqdn);
$host = $url->getHost();
if (str($host)->contains('sslip.io')) {
@@ -1603,29 +1606,34 @@ function validate_dns_entry(string $fqdn, Server $server)
if (!$is_dns_validation_enabled) {
return true;
}
$dnsServers = data_get($settings, 'custom_dns_servers');
$dnsServers = str($dnsServers)->explode(',');
$dns_servers = data_get($settings, 'custom_dns_servers');
$dns_servers = str($dns_servers)->explode(',');
if ($server->id === 0) {
$ip = data_get($settings, 'public_ipv4') || data_get($settings, 'public_ipv6') || $server->ip;
} else {
$ip = $server->ip;
}
$foundMatch = false;
$found_matching_ip = false;
$type = \PurplePixie\PhpDns\DNSTypes::NAME_A;
foreach ($dnsServers as $dnsServer) {
foreach ($dns_servers as $dns_server) {
try {
ray("Checking $host on $dnsServer");
$query = new DNSQuery($dnsServer);
ray("Checking $host on $dns_server");
$query = new DNSQuery($dns_server);
$results = $query->query($host, $type);
if ($results === false || $query->hasError()) {
ray("Error: " . $query->getLasterror());
} else {
foreach ($results as $result) {
if ($result->getType() == $type) {
if (ip_match($result->getData(), $cloudflare_ips->toArray(), $match)) {
ray("Found match in Cloudflare IPs: $match");
$found_matching_ip = true;
break;
}
if ($result->getData() === $ip) {
ray($host . " has IP address " . $result->getData());
ray($result->getString());
$foundMatch = true;
$found_matching_ip = true;
break;
}
}
@@ -1634,6 +1642,18 @@ function validate_dns_entry(string $fqdn, Server $server)
} catch (\Exception $e) {
}
}
ray("Found match: $foundMatch");
return $foundMatch;
ray("Found match: $found_matching_ip");
return $found_matching_ip;
}
function ip_match($ip, $cidrs, &$match = null)
{
foreach ((array) $cidrs as $cidr) {
list($subnet, $mask) = explode('/', $cidr);
if (((ip2long($ip) & ($mask = ~((1 << (32 - $mask)) - 1))) == (ip2long($subnet) & $mask))) {
$match = $cidr;
return true;
}
}
return false;
}

View File

@@ -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.191',
'release' => '4.0.0-beta.193',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),

View File

@@ -1,3 +1,3 @@
<?php
return '4.0.0-beta.191';
return '4.0.0-beta.193';

View File

@@ -52,7 +52,7 @@
<div class="w-64">
@if (!$server->isLocalhost())
<x-forms.checkbox instantSave
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
id="server.settings.is_cloudflare_tunnel" label="Cloudflare Tunnel" />
@if ($server->isSwarm())
<div class="pt-6"> Swarm support is in alpha version. </div>

View File

@@ -4,7 +4,7 @@
"version": "3.12.36"
},
"v4": {
"version": "4.0.0-beta.191"
"version": "4.0.0-beta.193"
}
}
}