2023-05-04 07:11:11 +00:00
< ? php
namespace App\Actions\Server ;
2025-01-31 11:27:29 +00:00
use App\Helpers\SslHelper ;
2023-05-04 07:11:11 +00:00
use App\Models\Server ;
2023-06-23 07:58:15 +00:00
use App\Models\StandaloneDocker ;
2024-06-10 20:43:34 +00:00
use Lorisleiva\Actions\Concerns\AsAction ;
2023-05-04 07:11:11 +00:00
class InstallDocker
{
2023-10-09 09:00:18 +00:00
use AsAction ;
2024-06-10 20:43:34 +00:00
2025-10-26 11:41:50 +00:00
private string $dockerVersion ;
2023-11-21 11:07:06 +00:00
public function handle ( Server $server )
2023-05-04 07:11:11 +00:00
{
2025-10-26 11:41:50 +00:00
$this -> dockerVersion = config ( 'constants.docker.minimum_required_version' );
2023-11-21 11:07:06 +00:00
$supported_os_type = $server -> validateOS ();
2024-06-10 20:43:34 +00:00
if ( ! $supported_os_type ) {
2025-01-07 14:31:43 +00:00
throw new \Exception ( 'Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.' );
2023-11-21 11:07:06 +00:00
}
2025-01-31 11:27:29 +00:00
2025-10-09 15:00:05 +00:00
if ( ! $server -> sslCertificates () -> where ( 'is_ca_certificate' , true ) -> exists ()) {
2025-01-31 11:27:29 +00:00
$serverCert = SslHelper :: generateSslCertificate (
commonName : 'Coolify CA Certificate' ,
2025-02-07 17:45:12 +00:00
serverId : $server -> id ,
2025-02-03 20:42:28 +00:00
isCaCertificate : true ,
2025-02-19 17:04:58 +00:00
validityDays : 10 * 365
2025-01-31 11:27:29 +00:00
);
2025-02-04 15:57:40 +00:00
$caCertPath = config ( 'constants.coolify.base_config_path' ) . '/ssl/' ;
2025-01-31 11:27:29 +00:00
2026-02-25 11:00:24 +00:00
$base64Cert = base64_encode ( $serverCert -> ssl_certificate );
2025-01-31 11:27:29 +00:00
$commands = collect ([
2025-02-04 15:57:40 +00:00
" mkdir -p $caCertPath " ,
" chown -R 9999:root $caCertPath " ,
" chmod -R 700 $caCertPath " ,
2025-02-07 17:28:58 +00:00
" rm -rf $caCertPath /coolify-ca.crt " ,
2026-02-25 11:00:24 +00:00
" echo ' { $base64Cert } ' | base64 -d | tee $caCertPath /coolify-ca.crt > /dev/null " ,
2025-02-04 15:57:40 +00:00
" chmod 644 $caCertPath /coolify-ca.crt " ,
2025-01-31 11:27:29 +00:00
]);
remote_process ( $commands , $server );
}
2023-09-05 13:43:56 +00:00
$config = base64_encode ( ' {
" log-driver " : " json-file " ,
" log-opts " : {
" max-size " : " 10m " ,
" max-file " : " 3 "
}
} ' );
2025-01-07 14:31:43 +00:00
$found = StandaloneDocker :: where ( 'server_id' , $server -> id );
if ( $found -> count () == 0 && $server -> id ) {
StandaloneDocker :: create ([
2023-09-09 13:30:46 +00:00
'name' => 'coolify' ,
'network' => 'coolify' ,
'server_id' => $server -> id ,
]);
}
2023-11-21 10:39:19 +00:00
$command = collect ([]);
2023-09-18 09:21:10 +00:00
if ( isDev () && $server -> id === 0 ) {
2023-11-21 10:39:19 +00:00
$command = $command -> merge ([
" echo 'Installing Docker Engine...' " ,
" echo 'Configuring Docker Engine (merging existing configuration with the required)...' " ,
2024-06-10 20:43:34 +00:00
'sleep 4' ,
2023-11-21 10:39:19 +00:00
" echo 'Restarting Docker Engine...' " ,
2024-06-10 20:43:34 +00:00
'ls -l /tmp' ,
2023-11-21 10:39:19 +00:00
]);
2024-06-10 20:43:34 +00:00
2024-02-05 13:40:54 +00:00
return remote_process ( $command , $server );
2025-01-07 13:52:08 +00:00
} else {
$command = $command -> merge ([
2025-01-07 14:31:43 +00:00
" echo 'Installing Docker Engine...' " ,
2025-10-26 11:41:50 +00:00
]);
if ( $supported_os_type -> contains ( 'debian' )) {
$command = $command -> merge ([ $this -> getDebianDockerInstallCommand ()]);
} elseif ( $supported_os_type -> contains ( 'rhel' )) {
$command = $command -> merge ([ $this -> getRhelDockerInstallCommand ()]);
} elseif ( $supported_os_type -> contains ( 'sles' )) {
$command = $command -> merge ([ $this -> getSuseDockerInstallCommand ()]);
2025-11-29 10:29:30 +00:00
} elseif ( $supported_os_type -> contains ( 'arch' )) {
$command = $command -> merge ([ $this -> getArchDockerInstallCommand ()]);
2025-10-26 11:41:50 +00:00
} else {
$command = $command -> merge ([ $this -> getGenericDockerInstallCommand ()]);
}
$command = $command -> merge ([
2025-01-07 14:31:43 +00:00
" echo 'Configuring Docker Engine (merging existing configuration with the required)...' " ,
'test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json "/etc/docker/daemon.json.original-$(date +"%Y%m%d-%H%M%S")"' ,
2025-09-15 15:55:08 +00:00
" test ! -s /etc/docker/daemon.json && echo ' { $config } ' | base64 -d | tee /etc/docker/daemon.json > /dev/null " ,
" echo ' { $config } ' | base64 -d | tee /etc/docker/daemon.json.coolify > /dev/null " ,
2025-01-07 14:31:43 +00:00
'jq . /etc/docker/daemon.json.coolify | tee /etc/docker/daemon.json.coolify.pretty > /dev/null' ,
'mv /etc/docker/daemon.json.coolify.pretty /etc/docker/daemon.json.coolify' ,
" jq -s '.[0] * .[1]' /etc/docker/daemon.json.coolify /etc/docker/daemon.json | tee /etc/docker/daemon.json.appended > /dev/null " ,
'mv /etc/docker/daemon.json.appended /etc/docker/daemon.json' ,
" echo 'Restarting Docker Engine...' " ,
'systemctl enable docker >/dev/null 2>&1 || true' ,
'systemctl restart docker' ,
2023-11-21 10:39:19 +00:00
]);
2025-01-07 14:31:43 +00:00
if ( $server -> isSwarm ()) {
$command = $command -> merge ([
'docker network create --attachable --driver overlay coolify-overlay >/dev/null 2>&1 || true' ,
]);
} else {
$command = $command -> merge ([
'docker network create --attachable coolify >/dev/null 2>&1 || true' ,
]);
$command = $command -> merge ([
" echo 'Done!' " ,
]);
}
2025-01-07 13:52:08 +00:00
2025-01-07 14:31:43 +00:00
return remote_process ( $command , $server );
}
2023-05-04 07:11:11 +00:00
}
2025-10-26 11:41:50 +00:00
private function getDebianDockerInstallCommand () : string
{
2025-10-28 08:31:32 +00:00
return " curl --max-time 300 --retry 3 https://releases.rancher.com/install-docker/ { $this -> dockerVersion } .sh | sh || curl --max-time 300 --retry 3 https://get.docker.com | sh -s -- --version { $this -> dockerVersion } || ( " .
2026-01-09 09:04:42 +00:00
'. /etc/os-release && ' .
2025-10-26 11:41:50 +00:00
'install -m 0755 -d /etc/apt/keyrings && ' .
2026-01-09 09:04:42 +00:00
'curl -fsSL https://download.docker.com/linux/${ID}/gpg -o /etc/apt/keyrings/docker.asc && ' .
2025-10-26 11:41:50 +00:00
'chmod a+r /etc/apt/keyrings/docker.asc && ' .
2026-01-09 09:04:42 +00:00
'echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list && ' .
2025-10-26 11:41:50 +00:00
'apt-get update && ' .
'apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin' .
')' ;
}
private function getRhelDockerInstallCommand () : string
{
return " curl https://releases.rancher.com/install-docker/ { $this -> dockerVersion } .sh | sh || curl https://get.docker.com | sh -s -- --version { $this -> dockerVersion } || ( " .
'dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && ' .
'dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin && ' .
'systemctl start docker && ' .
'systemctl enable docker' .
')' ;
}
private function getSuseDockerInstallCommand () : string
{
return " curl https://releases.rancher.com/install-docker/ { $this -> dockerVersion } .sh | sh || curl https://get.docker.com | sh -s -- --version { $this -> dockerVersion } || ( " .
'zypper addrepo https://download.docker.com/linux/sles/docker-ce.repo && ' .
'zypper refresh && ' .
'zypper install -y --no-confirm docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin && ' .
'systemctl start docker && ' .
'systemctl enable docker' .
')' ;
}
2025-12-08 08:02:00 +00:00
private function getArchDockerInstallCommand () : string
{
// Use -Syu to perform full system upgrade before installing Docker
// Partial upgrades (-Sy without -u) are discouraged on Arch Linux
// as they can lead to broken dependencies and system instability
2025-12-08 08:17:24 +00:00
// Use --needed to skip reinstalling packages that are already up-to-date (idempotent)
return 'pacman -Syu --noconfirm --needed docker docker-compose && ' .
2025-12-08 08:02:00 +00:00
'systemctl enable docker.service && ' .
'systemctl start docker.service' ;
}
2025-12-11 08:25:35 +00:00
private function getGenericDockerInstallCommand () : string
{
2025-12-11 11:12:43 +00:00
return " curl --max-time 300 --retry 3 https://releases.rancher.com/install-docker/ { $this -> dockerVersion } .sh | sh || curl --max-time 300 --retry 3 https://get.docker.com | sh -s -- --version { $this -> dockerVersion } " ;
2025-12-11 08:25:35 +00:00
}
2023-05-04 07:11:11 +00:00
}