mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-16 12:33:03 +00:00
@@ -54,7 +54,7 @@ Special thanks to our biggest sponsors!
|
|||||||
* [Latitude](https://latitude.sh/?ref=coolify.io) - A cloud computing platform offering bare metal servers and cloud instances for developers and businesses.
|
* [Latitude](https://latitude.sh/?ref=coolify.io) - A cloud computing platform offering bare metal servers and cloud instances for developers and businesses.
|
||||||
* [Brand Dev](https://brand.dev/?ref=coolify.io) - A web development agency specializing in creating custom digital experiences and brand identities.
|
* [Brand Dev](https://brand.dev/?ref=coolify.io) - A web development agency specializing in creating custom digital experiences and brand identities.
|
||||||
* [Jobscollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - A job search platform connecting professionals with remote work opportunities across various industries.
|
* [Jobscollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - A job search platform connecting professionals with remote work opportunities across various industries.
|
||||||
* [Hostinger](https://hostinger.com?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools.
|
* [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools.
|
||||||
* [Glueops](https://www.glueops.dev/?ref=coolify.io) - A DevOps consulting company providing infrastructure automation and cloud optimization services.
|
* [Glueops](https://www.glueops.dev/?ref=coolify.io) - A DevOps consulting company providing infrastructure automation and cloud optimization services.
|
||||||
* [Ubicloud](https://ubicloud.com/?ref=coolify.io) - An open-source alternative to hyperscale cloud providers, offering high-performance cloud computing services.
|
* [Ubicloud](https://ubicloud.com/?ref=coolify.io) - An open-source alternative to hyperscale cloud providers, offering high-performance cloud computing services.
|
||||||
* [Juxtdigital](https://juxtdigital.dev/?ref=coolify.io) - A digital agency offering web development, design, and digital marketing services for businesses.
|
* [Juxtdigital](https://juxtdigital.dev/?ref=coolify.io) - A digital agency offering web development, design, and digital marketing services for businesses.
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
public function middleware(): array
|
public function middleware(): array
|
||||||
{
|
{
|
||||||
return [(new WithoutOverlapping($this->server->uuid))];
|
return [(new WithoutOverlapping($this->server->id))];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function uniqueId(): int
|
public function uniqueId(): int
|
||||||
{
|
{
|
||||||
return $this->server->uuid;
|
return $this->server->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ class Index extends Component
|
|||||||
}
|
}
|
||||||
$this->privateKeyName = generate_random_name();
|
$this->privateKeyName = generate_random_name();
|
||||||
$this->remoteServerName = generate_random_name();
|
$this->remoteServerName = generate_random_name();
|
||||||
|
$this->remoteServerPort = $this->remoteServerPort;
|
||||||
|
$this->remoteServerUser = $this->remoteServerUser;
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
|
$this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
@@ -154,6 +156,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
|
$this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
|
||||||
if ($this->servers->count() > 0) {
|
if ($this->servers->count() > 0) {
|
||||||
$this->selectedExistingServer = $this->servers->first()->id;
|
$this->selectedExistingServer = $this->servers->first()->id;
|
||||||
|
$this->updateServerDetails();
|
||||||
$this->currentState = 'select-existing-server';
|
$this->currentState = 'select-existing-server';
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -173,9 +176,18 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
}
|
}
|
||||||
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
|
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
|
||||||
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
|
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
|
||||||
|
$this->updateServerDetails();
|
||||||
$this->currentState = 'validate-server';
|
$this->currentState = 'validate-server';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function updateServerDetails()
|
||||||
|
{
|
||||||
|
if ($this->createdServer) {
|
||||||
|
$this->remoteServerPort = $this->createdServer->port;
|
||||||
|
$this->remoteServerUser = $this->createdServer->user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getProxyType()
|
public function getProxyType()
|
||||||
{
|
{
|
||||||
// Set Default Proxy Type
|
// Set Default Proxy Type
|
||||||
@@ -235,11 +247,12 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
public function saveServer()
|
public function saveServer()
|
||||||
{
|
{
|
||||||
$this->validate([
|
$this->validate([
|
||||||
'remoteServerName' => 'required',
|
'remoteServerName' => 'required|string',
|
||||||
'remoteServerHost' => 'required',
|
'remoteServerHost' => 'required|string',
|
||||||
'remoteServerPort' => 'required|integer',
|
'remoteServerPort' => 'required|integer',
|
||||||
'remoteServerUser' => 'required',
|
'remoteServerUser' => 'required|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->privateKey = formatPrivateKey($this->privateKey);
|
$this->privateKey = formatPrivateKey($this->privateKey);
|
||||||
$foundServer = Server::whereIp($this->remoteServerHost)->first();
|
$foundServer = Server::whereIp($this->remoteServerHost)->first();
|
||||||
if ($foundServer) {
|
if ($foundServer) {
|
||||||
@@ -277,9 +290,12 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->createdServer->settings()->update([
|
$this->createdServer->settings()->update([
|
||||||
'is_reachable' => true,
|
'is_reachable' => true,
|
||||||
]);
|
]);
|
||||||
|
$this->serverReachable = true;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->serverReachable = false;
|
$this->serverReachable = false;
|
||||||
$this->createdServer->delete();
|
$this->createdServer->settings()->update([
|
||||||
|
'is_reachable' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
return handleError(error: $e, livewire: $this);
|
return handleError(error: $e, livewire: $this);
|
||||||
}
|
}
|
||||||
@@ -296,6 +312,10 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
]);
|
]);
|
||||||
$this->getProxyType();
|
$this->getProxyType();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
$this->createdServer->settings()->update([
|
||||||
|
'is_usable' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
return handleError(error: $e, livewire: $this);
|
return handleError(error: $e, livewire: $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,6 +369,21 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function saveAndValidateServer()
|
||||||
|
{
|
||||||
|
$this->validate([
|
||||||
|
'remoteServerPort' => 'required|integer|min:1|max:65535',
|
||||||
|
'remoteServerUser' => 'required|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->createdServer->update([
|
||||||
|
'port' => $this->remoteServerPort,
|
||||||
|
'user' => $this->remoteServerUser,
|
||||||
|
'timezone' => 'UTC',
|
||||||
|
]);
|
||||||
|
$this->validateServer();
|
||||||
|
}
|
||||||
|
|
||||||
private function createNewPrivateKey()
|
private function createNewPrivateKey()
|
||||||
{
|
{
|
||||||
$this->privateKeyName = generate_random_name();
|
$this->privateKeyName = generate_random_name();
|
||||||
|
|||||||
@@ -112,6 +112,16 @@ class Server extends BaseModel
|
|||||||
'proxy',
|
'proxy',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'ip',
|
||||||
|
'port',
|
||||||
|
'user',
|
||||||
|
'description',
|
||||||
|
'private_key_id',
|
||||||
|
'team_id',
|
||||||
|
];
|
||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
public static function isReachable()
|
public static function isReachable()
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ const SUPPORTED_OS = [
|
|||||||
'centos fedora rhel ol rocky amzn almalinux',
|
'centos fedora rhel ol rocky amzn almalinux',
|
||||||
'sles opensuse-leap opensuse-tumbleweed',
|
'sles opensuse-leap opensuse-tumbleweed',
|
||||||
'arch',
|
'arch',
|
||||||
|
'alpine',
|
||||||
];
|
];
|
||||||
|
|
||||||
const SHARED_VARIABLE_TYPES = ['team', 'project', 'environment'];
|
const SHARED_VARIABLE_TYPES = ['team', 'project', 'environment'];
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.332',
|
'release' => '4.0.0-beta.333',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.332';
|
return '4.0.0-beta.333';
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ if [ $EUID != 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn) ;;
|
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||||
*)
|
*)
|
||||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
echo "This script only supports Debian, Redhat, Arch Linux, Alpine Linux, or SLES based operating systems for now."
|
||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -90,6 +90,11 @@ case "$OS_TYPE" in
|
|||||||
arch)
|
arch)
|
||||||
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
||||||
;;
|
;;
|
||||||
|
alpine)
|
||||||
|
sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
|
||||||
|
apk update >/dev/null
|
||||||
|
apk add curl wget git jq >/dev/null
|
||||||
|
;;
|
||||||
ubuntu | debian | raspbian)
|
ubuntu | debian | raspbian)
|
||||||
apt-get update -y >/dev/null
|
apt-get update -y >/dev/null
|
||||||
apt-get install -y curl wget git jq >/dev/null
|
apt-get install -y curl wget git jq >/dev/null
|
||||||
@@ -172,70 +177,74 @@ if [ -x "$(command -v snap)" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
# Almalinux
|
case "$OS_TYPE" in
|
||||||
if [ "$OS_TYPE" == 'almalinux' ]; then
|
"almalinux")
|
||||||
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
|
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-compose-plugin
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
echo "Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
echo "Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
systemctl start docker
|
systemctl start docker
|
||||||
systemctl enable docker
|
systemctl enable docker
|
||||||
else
|
;;
|
||||||
set +e
|
"alpine")
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
apk add docker docker-cli-compose
|
||||||
echo "Docker is not installed. Installing Docker."
|
rc-update add docker default
|
||||||
# Arch Linux
|
service docker start
|
||||||
if [ "$OS_TYPE" = "arch" ]; then
|
if [ -x "$(command -v docker)" ]; then
|
||||||
pacman -Sy docker docker-compose --noconfirm
|
echo "Docker installed successfully."
|
||||||
systemctl enable docker.service
|
else
|
||||||
|
echo "Failed to install Docker with apk. Try to install it manually."
|
||||||
|
echo "Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"arch")
|
||||||
|
pacman -Sy docker docker-compose --noconfirm
|
||||||
|
systemctl enable docker.service
|
||||||
|
if [ -x "$(command -v docker)" ]; then
|
||||||
|
echo "Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo "Failed to install Docker with pacman. Try to install it manually."
|
||||||
|
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"amzn")
|
||||||
|
dnf install docker -y
|
||||||
|
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
||||||
|
mkdir -p $DOCKER_CONFIG/cli-plugins
|
||||||
|
curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||||
|
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||||
|
systemctl start docker
|
||||||
|
systemctl enable docker
|
||||||
|
if [ -x "$(command -v docker)" ]; then
|
||||||
|
echo "Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo "Failed to install Docker with dnf. Try to install it manually."
|
||||||
|
echo "Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Automated Docker installation
|
||||||
|
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
||||||
|
if [ -x "$(command -v docker)" ]; then
|
||||||
|
echo "Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo "Docker installation failed with Rancher script. Trying with official script."
|
||||||
|
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
||||||
if [ -x "$(command -v docker)" ]; then
|
if [ -x "$(command -v docker)" ]; then
|
||||||
echo "Docker installed successfully."
|
echo "Docker installed successfully."
|
||||||
else
|
else
|
||||||
echo "Failed to install Docker with pacman. Try to install it manually."
|
echo "Docker installation failed with official script."
|
||||||
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
echo "Maybe your OS is not supported?"
|
||||||
exit
|
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
fi
|
exit 1
|
||||||
else
|
|
||||||
# Amazon Linux 2023
|
|
||||||
if [ "$OS_TYPE" = "amzn" ]; then
|
|
||||||
dnf install docker -y
|
|
||||||
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
|
||||||
mkdir -p $DOCKER_CONFIG/cli-plugins
|
|
||||||
curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose
|
|
||||||
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
|
|
||||||
systemctl start docker
|
|
||||||
systemctl enable docker
|
|
||||||
if [ -x "$(command -v docker)" ]; then
|
|
||||||
echo "Docker installed successfully."
|
|
||||||
else
|
|
||||||
echo "Failed to install Docker with pacman. Try to install it manually."
|
|
||||||
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Automated Docker installation
|
|
||||||
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
|
||||||
if [ -x "$(command -v docker)" ]; then
|
|
||||||
echo "Docker installed successfully."
|
|
||||||
else
|
|
||||||
echo "Docker installation failed with Rancher script. Trying with official script."
|
|
||||||
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
|
||||||
if [ -x "$(command -v docker)" ]; then
|
|
||||||
echo "Docker installed successfully."
|
|
||||||
else
|
|
||||||
echo "Docker installation failed with official script."
|
|
||||||
echo "Maybe your OS is not supported?"
|
|
||||||
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
esac
|
||||||
set -e
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "-------------"
|
echo -e "-------------"
|
||||||
@@ -267,17 +276,50 @@ if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify
|
|||||||
fi
|
fi
|
||||||
mv "$TEMP_FILE" /etc/docker/daemon.json
|
mv "$TEMP_FILE" /etc/docker/daemon.json
|
||||||
|
|
||||||
|
restart_docker_service() {
|
||||||
|
|
||||||
|
# Check if systemctl is available
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo "Using systemctl to restart Docker..."
|
||||||
|
systemctl restart docker
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Docker restarted successfully using systemctl."
|
||||||
|
else
|
||||||
|
echo "Failed to restart Docker using systemctl."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if service command is available
|
||||||
|
elif command -v service >/dev/null 2>&1; then
|
||||||
|
echo "Using service command to restart Docker..."
|
||||||
|
service docker restart
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Docker restarted successfully using service."
|
||||||
|
else
|
||||||
|
echo "Failed to restart Docker using service."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If neither systemctl nor service is available
|
||||||
|
else
|
||||||
|
echo "Neither systemctl nor service command is available on this system."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||||
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
||||||
if [ "$DIFF" != "" ]; then
|
if [ "$DIFF" != "" ]; then
|
||||||
echo "Docker configuration updated, restart docker daemon..."
|
echo "Docker configuration updated, restart docker daemon..."
|
||||||
systemctl restart docker
|
restart_docker_service
|
||||||
else
|
else
|
||||||
echo "Docker configuration is up to date."
|
echo "Docker configuration is up to date."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Docker configuration updated, restart docker daemon..."
|
echo "Docker configuration updated, restart docker daemon..."
|
||||||
systemctl restart docker
|
restart_docker_service
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "-------------"
|
echo -e "-------------"
|
||||||
@@ -296,28 +338,35 @@ curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
|||||||
curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||||
|
|
||||||
# Copy .env.example if .env does not exist
|
# Copy .env.example if .env does not exist
|
||||||
if [ ! -f $ENV_FILE ]; then
|
if [ -f $ENV_FILE ]; then
|
||||||
cp /data/coolify/source/.env.production $ENV_FILE
|
echo "File exists: $ENV_FILE"
|
||||||
# Generate a secure APP_ID and APP_KEY
|
cat $ENV_FILE
|
||||||
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE"
|
echo "Copying .env to .env-$DATE"
|
||||||
sed -i "s|^APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|" "$ENV_FILE"
|
cp $ENV_FILE $ENV_FILE-$DATE
|
||||||
|
else
|
||||||
|
echo "File does not exist: $ENV_FILE"
|
||||||
|
echo "Copying .env.production to .env-$DATE"
|
||||||
|
cp /data/coolify/source/.env.production $ENV_FILE-$DATE
|
||||||
|
# Generate a secure APP_ID and APP_KEY
|
||||||
|
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
# Generate a secure Postgres DB username and password
|
# Generate a secure Postgres DB username and password
|
||||||
# Causes issues: database "random-user" does not exist
|
# Causes issues: database "random-user" does not exist
|
||||||
# sed -i "s|^DB_USERNAME=.*|DB_USERNAME=$(openssl rand -hex 16)|" "$ENV_FILE"
|
# sed -i "s|^DB_USERNAME=.*|DB_USERNAME=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||||
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE"
|
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
# Generate a secure Redis password
|
# Generate a secure Redis password
|
||||||
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE"
|
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
# Generate secure Pusher credentials
|
# Generate secure Pusher credentials
|
||||||
sed -i "s|^PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|" "$ENV_FILE"
|
sed -i "s|^PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
sed -i "s|^PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|" "$ENV_FILE"
|
sed -i "s|^PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE"
|
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production > $ENV_FILE
|
||||||
|
|
||||||
if [ "$AUTOUPDATE" = "false" ]; then
|
if [ "$AUTOUPDATE" = "false" ]; then
|
||||||
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||||
@@ -350,7 +399,7 @@ if ! grep -qw "root@coolify" ~/.ssh/authorized_keys; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}"
|
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}"
|
||||||
|
rm -f $ENV_FILE-$DATE
|
||||||
echo "Waiting for 20 seconds for Coolify to be ready..."
|
echo "Waiting for 20 seconds for Coolify to be ready..."
|
||||||
|
|
||||||
sleep 20
|
sleep 20
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.p
|
|||||||
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||||
|
|
||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
awk -F '=' '!seen[$1]++' /data/coolify/source/.env /data/coolify/source/.env.production > /data/coolify/source/.env.tmp && mv /data/coolify/source/.env.tmp /data/coolify/source/.env
|
||||||
|
|
||||||
# Check if PUSHER_APP_ID or PUSHER_APP_KEY or PUSHER_APP_SECRET is empty in /data/coolify/source/.env
|
# Check if PUSHER_APP_ID or PUSHER_APP_KEY or PUSHER_APP_SECRET is empty in /data/coolify/source/.env
|
||||||
if grep -q "PUSHER_APP_ID=$" /data/coolify/source/.env; then
|
if grep -q "PUSHER_APP_ID=$" /data/coolify/source/.env; then
|
||||||
|
|||||||
@@ -28,25 +28,33 @@
|
|||||||
<x-highlighted text="Self-hosting with superpowers!" /></span>
|
<x-highlighted text="Self-hosting with superpowers!" /></span>
|
||||||
</x-slot:question>
|
</x-slot:question>
|
||||||
<x-slot:explanation>
|
<x-slot:explanation>
|
||||||
<p><x-highlighted text="Task automation:" /> You don't need to manage your servers anymore.
|
<p>
|
||||||
|
<x-highlighted text="Task automation:" /> You don't need to manage your servers anymore.
|
||||||
Coolify does
|
Coolify does
|
||||||
it for you.</p>
|
it for you.
|
||||||
<p><x-highlighted text="No vendor lock-in:" /> All configurations are stored on your servers, so
|
</p>
|
||||||
everything works without a connection to Coolify (except integrations and automations).</p>
|
<p>
|
||||||
<p><x-highlighted text="Monitoring:" />You can get notified on your favourite platforms
|
<x-highlighted text="No vendor lock-in:" /> All configurations are stored on your servers, so
|
||||||
|
everything works without a connection to Coolify (except integrations and automations).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<x-highlighted text="Monitoring:" />You can get notified on your favourite platforms
|
||||||
(Discord,
|
(Discord,
|
||||||
Telegram, Email, etc.) when something goes wrong, or an action is needed from your side.</p>
|
Telegram, Email, etc.) when something goes wrong, or an action is needed from your side.
|
||||||
|
</p>
|
||||||
</x-slot:explanation>
|
</x-slot:explanation>
|
||||||
<x-slot:actions>
|
<x-slot:actions>
|
||||||
<x-forms.button class="justify-center lg:w-64 box-boarding" wire:click="explanation">Next
|
<x-forms.button class="justify-center w-64 box-boarding" wire:click="explanation">Next
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</x-slot:actions>
|
</x-slot:actions>
|
||||||
</x-boarding-step>
|
</x-boarding-step>
|
||||||
@elseif ($currentState === 'select-server-type')
|
@elseif ($currentState === 'select-server-type')
|
||||||
<x-boarding-step title="Server">
|
<x-boarding-step title="Server">
|
||||||
<x-slot:question>
|
<x-slot:question>
|
||||||
Do you want to deploy your resources to your <x-highlighted text="Localhost" />
|
Do you want to deploy your resources to your
|
||||||
or to a <x-highlighted text="Remote Server" />?
|
<x-highlighted text="Localhost" />
|
||||||
|
or to a
|
||||||
|
<x-highlighted text="Remote Server" />?
|
||||||
</x-slot:question>
|
</x-slot:question>
|
||||||
<x-slot:actions>
|
<x-slot:actions>
|
||||||
<x-forms.button class="justify-center w-64 box-boarding" wire:target="setServerType('localhost')"
|
<x-forms.button class="justify-center w-64 box-boarding" wire:target="setServerType('localhost')"
|
||||||
@@ -56,32 +64,66 @@
|
|||||||
<x-forms.button class="justify-center w-64 box-boarding " wire:target="setServerType('remote')"
|
<x-forms.button class="justify-center w-64 box-boarding " wire:target="setServerType('remote')"
|
||||||
wire:click="setServerType('remote')">Remote Server
|
wire:click="setServerType('remote')">Remote Server
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
|
|
||||||
@if (!$serverReachable)
|
@if (!$serverReachable)
|
||||||
Localhost is not reachable with the following public key.
|
<div class="mt-6 p-4 border border-error rounded-lg text-gray-800 dark:text-gray-200">
|
||||||
<br /> <br />
|
<h2 class="text-lg font-bold mb-2">Server is not reachable</h2>
|
||||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for
|
<p class="mb-4">Please check the connection details below and correct them if they are
|
||||||
user or skip the boarding process and add a new private key manually to Coolify and to the
|
incorrect.</p>
|
||||||
server.
|
|
||||||
<br />
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||||
Check this <a target="_blank" class="underline"
|
<x-forms.input placeholder="Default is 22" label="Port" id="remoteServerPort"
|
||||||
href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further
|
wire:model="remoteServerPort" :value="$remoteServerPort" />
|
||||||
help.
|
<div>
|
||||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
<x-forms.input placeholder="Default is root" label="User" id="remoteServerUser"
|
||||||
<x-forms.button class="lg:w-64 box-boarding" wire:target="setServerType('localhost')"
|
wire:model="remoteServerUser" :value="$remoteServerUser" />
|
||||||
wire:click="setServerType('localhost')">Check again
|
<p class="text-xs mt-1">
|
||||||
</x-forms.button>
|
Non-root user is experimental:
|
||||||
|
<a class="font-bold underline" target="_blank"
|
||||||
|
href="https://coolify.io/docs/knowledge-base/server/non-root-user">docs</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<p class="mb-2">If the connection details are correct, please ensure:</p>
|
||||||
|
<ul class="list-disc list-inside">
|
||||||
|
<li>The correct public key is in your <code
|
||||||
|
class="bg-red-200 dark:bg-red-900 px-1 rounded">~/.ssh/authorized_keys</code>
|
||||||
|
file for the specified user</li>
|
||||||
|
<li>Or skip the boarding process and manually add a new private key to Coolify and
|
||||||
|
the server</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="mb-4">
|
||||||
|
For more help, check this <a target="_blank" class="underline font-semibold"
|
||||||
|
href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<x-forms.input readonly id="serverPublicKey" class="mb-4"
|
||||||
|
label="Current Public Key"></x-forms.input>
|
||||||
|
|
||||||
|
<x-forms.button class="w-full box-boarding" wire:click="saveAndValidateServer">
|
||||||
|
Check Again
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</x-slot:actions>
|
</x-slot:actions>
|
||||||
<x-slot:explanation>
|
<x-slot:explanation>
|
||||||
<p>Servers are the main building blocks, as they will host your applications, databases,
|
<p>Servers are the main building blocks, as they will host your applications, databases,
|
||||||
services, called resources. Any CPU intensive process will use the server's CPU where you
|
services, called resources. Any CPU intensive process will use the server's CPU where you
|
||||||
are deploying your resources.</p>
|
are deploying your resources.</p>
|
||||||
<p><x-highlighted text="Localhost" /> is the server where Coolify is running on. It is not
|
<p>
|
||||||
|
<x-highlighted text="Localhost" /> is the server where Coolify is running on. It is not
|
||||||
recommended to use one server
|
recommended to use one server
|
||||||
for everything.</p>
|
for everything.
|
||||||
<p><x-highlighted text="A remote server" /> is a server reachable through SSH. It can be hosted
|
</p>
|
||||||
|
<p>
|
||||||
|
<x-highlighted text="A remote server" /> is a server reachable through SSH. It can be hosted
|
||||||
at home, or from any cloud
|
at home, or from any cloud
|
||||||
provider.</p>
|
provider.
|
||||||
|
</p>
|
||||||
</x-slot:explanation>
|
</x-slot:explanation>
|
||||||
</x-boarding-step>
|
</x-boarding-step>
|
||||||
@elseif ($currentState === 'private-key')
|
@elseif ($currentState === 'private-key')
|
||||||
@@ -126,10 +168,7 @@
|
|||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div>
|
<div>
|
||||||
<x-forms.button class="justify-center w-64 box-boarding" wire:click="createNewServer">No
|
<x-forms.button class="justify-center w-64 box-boarding" wire:click="createNewServer">No
|
||||||
(create
|
(create one for me)
|
||||||
one
|
|
||||||
for
|
|
||||||
me)
|
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -145,20 +184,48 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (!$serverReachable)
|
@if (!$serverReachable)
|
||||||
This server is not reachable with the following public key.
|
<div class="mt-6 p-4 bg-red-100 dark:bg-red-950 rounded-lg text-gray-800 dark:text-gray-200">
|
||||||
<br /> <br />
|
<h2 class="text-lg font-bold mb-2">Server is not reachable</h2>
|
||||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for
|
<p class="mb-4">Please check the connection details below and correct them if they are
|
||||||
user or skip the boarding process and add a new private key manually to Coolify and to the
|
incorrect.</p>
|
||||||
server.
|
|
||||||
<br />
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||||
Check this <a target="_blank" class="underline"
|
<x-forms.input placeholder="Default is 22" label="Port" id="remoteServerPort"
|
||||||
href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further
|
wire:model="remoteServerPort" :value="$remoteServerPort" />
|
||||||
help.
|
<div>
|
||||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
<x-forms.input placeholder="Default is root" label="User" id="remoteServerUser"
|
||||||
<x-forms.button class="w-64 box-boarding" wire:target="validateServer"
|
wire:model="remoteServerUser" :value="$remoteServerUser" />
|
||||||
wire:click="validateServer">Check
|
<p class="text-xs mt-1">
|
||||||
again
|
Non-root user is experimental:
|
||||||
</x-forms.button>
|
<a class="font-bold underline" target="_blank"
|
||||||
|
href="https://coolify.io/docs/knowledge-base/server/non-root-user">docs</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<p class="mb-2">If the connection details are correct, please ensure:</p>
|
||||||
|
<ul class="list-disc list-inside">
|
||||||
|
<li>The correct public key is in your <code
|
||||||
|
class="bg-red-200 dark:bg-red-900 px-1 rounded">~/.ssh/authorized_keys</code>
|
||||||
|
file for the specified user</li>
|
||||||
|
<li>Or skip the boarding process and manually add a new private key to Coolify and
|
||||||
|
the server</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="mb-4">
|
||||||
|
For more help, check this <a target="_blank" class="underline font-semibold"
|
||||||
|
href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<x-forms.input readonly id="serverPublicKey" class="mb-4"
|
||||||
|
label="Current Public Key"></x-forms.input>
|
||||||
|
|
||||||
|
<x-forms.button class="w-full md:w-auto box-boarding" wire:click="saveAndValidateServer">
|
||||||
|
Check again
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</x-slot:actions>
|
</x-slot:actions>
|
||||||
<x-slot:explanation>
|
<x-slot:explanation>
|
||||||
@@ -180,8 +247,8 @@
|
|||||||
label="Name" id="privateKeyName" />
|
label="Name" id="privateKeyName" />
|
||||||
<x-forms.input placeholder="Description, so others will know more about this."
|
<x-forms.input placeholder="Description, so others will know more about this."
|
||||||
label="Description" id="privateKeyDescription" />
|
label="Description" id="privateKeyDescription" />
|
||||||
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----" label="Private Key"
|
<x-forms.textarea required placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
|
||||||
id="privateKey" />
|
label="Private Key" id="privateKey" />
|
||||||
@if ($privateKeyType === 'create')
|
@if ($privateKeyType === 'create')
|
||||||
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
<x-forms.textarea rows="7" readonly label="Public Key" id="publicKey" />
|
||||||
<span class="font-bold dark:text-warning">ACTION REQUIRED: Copy the 'Public Key' to your
|
<span class="font-bold dark:text-warning">ACTION REQUIRED: Copy the 'Public Key' to your
|
||||||
@@ -209,27 +276,37 @@
|
|||||||
<form wire:submit='saveServer' class="flex flex-col w-full gap-4 lg:pr-10">
|
<form wire:submit='saveServer' class="flex flex-col w-full gap-4 lg:pr-10">
|
||||||
<div class="flex flex-col gap-2 lg:flex-row">
|
<div class="flex flex-col gap-2 lg:flex-row">
|
||||||
<x-forms.input required placeholder="Choose a name for your Server. Could be anything."
|
<x-forms.input required placeholder="Choose a name for your Server. Could be anything."
|
||||||
label="Name" id="remoteServerName" />
|
label="Name" id="remoteServerName" wire:model="remoteServerName" />
|
||||||
<x-forms.input placeholder="Description, so others will know more about this."
|
<x-forms.input placeholder="Description, so others will know more about this."
|
||||||
label="Description" id="remoteServerDescription" />
|
label="Description" id="remoteServerDescription"
|
||||||
|
wire:model="remoteServerDescription" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2 lg:flex-row ">
|
<div class="flex flex-col gap-2 lg:flex-row ">
|
||||||
<x-forms.input required placeholder="127.0.0.1" label="IP Address" id="remoteServerHost" />
|
<x-forms.input required placeholder="127.0.0.1" label="IP Address" id="remoteServerHost"
|
||||||
<x-forms.input required placeholder="Port number of your server. Default is 22."
|
wire:model="remoteServerHost" />
|
||||||
label="Port" id="remoteServerPort" />
|
</div>
|
||||||
<div class="w-full">
|
<div x-data="{ showAdvanced: false }" class="flex flex-col gap-2">
|
||||||
<x-forms.input required placeholder="User to connect to your server. Default is root."
|
<button @click="showAdvanced = !showAdvanced" type="button"
|
||||||
label="User" id="remoteServerUser" />
|
class="text-left text-sm text-gray-600 dark:text-gray-300 hover:underline">
|
||||||
<div class="text-xs dark:text-warning text-coollabs ">Non-root user is experimental: <a
|
Advanced Settings
|
||||||
class="font-bold underline" target="_blank"
|
</button>
|
||||||
href="https://coolify.io/docs/knowledge-base/server/non-root-user">docs</a>.
|
<div x-show="showAdvanced" class="flex flex-col gap-2 lg:flex-row">
|
||||||
|
<x-forms.input placeholder="Port number of your server. Default is 22." label="Port"
|
||||||
|
id="remoteServerPort" wire:model="remoteServerPort" />
|
||||||
|
<div class="w-full">
|
||||||
|
<x-forms.input placeholder="Default is root." label="User"
|
||||||
|
id="remoteServerUser" wire:model="remoteServerUser" />
|
||||||
|
<div class="text-xs text-gray-600 dark:text-gray-300">Non-root user is
|
||||||
|
experimental: <a class="font-bold underline" target="_blank"
|
||||||
|
href="https://coolify.io/docs/knowledge-base/server/non-root-user">docs</a>.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="lg:w-64">
|
<div class="lg:w-64">
|
||||||
<x-forms.checkbox
|
<x-forms.checkbox
|
||||||
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='dark: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='dark:text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
||||||
id="isCloudflareTunnel" label="Cloudflare Tunnel" />
|
id="isCloudflareTunnel" label="Cloudflare Tunnel" wire:model="isCloudflareTunnel" />
|
||||||
</div>
|
</div>
|
||||||
<x-forms.button type="submit">Continue</x-forms.button>
|
<x-forms.button type="submit">Continue</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
@@ -329,5 +406,4 @@
|
|||||||
<livewire:help />
|
<livewire:help />
|
||||||
</x-modal-input>
|
</x-modal-input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ if [ $EUID != 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn) ;;
|
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||||
*)
|
*)
|
||||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
echo "This script only supports Debian, Redhat, Arch Linux, Alpine Linux, or SLES based operating systems for now."
|
||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -90,6 +90,11 @@ case "$OS_TYPE" in
|
|||||||
arch)
|
arch)
|
||||||
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
||||||
;;
|
;;
|
||||||
|
alpine)
|
||||||
|
sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
|
||||||
|
apk update >/dev/null
|
||||||
|
apk add curl wget git jq >/dev/null
|
||||||
|
;;
|
||||||
ubuntu | debian | raspbian)
|
ubuntu | debian | raspbian)
|
||||||
apt-get update -y >/dev/null
|
apt-get update -y >/dev/null
|
||||||
apt-get install -y curl wget git jq >/dev/null
|
apt-get install -y curl wget git jq >/dev/null
|
||||||
@@ -172,70 +177,74 @@ if [ -x "$(command -v snap)" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
# Almalinux
|
case "$OS_TYPE" in
|
||||||
if [ "$OS_TYPE" == 'almalinux' ]; then
|
"almalinux")
|
||||||
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
|
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-compose-plugin
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
echo "Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
echo "Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
systemctl start docker
|
systemctl start docker
|
||||||
systemctl enable docker
|
systemctl enable docker
|
||||||
else
|
;;
|
||||||
set +e
|
"alpine")
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
apk add docker docker-cli-compose
|
||||||
echo "Docker is not installed. Installing Docker."
|
rc-update add docker default
|
||||||
# Arch Linux
|
service docker start
|
||||||
if [ "$OS_TYPE" = "arch" ]; then
|
if [ -x "$(command -v docker)" ]; then
|
||||||
pacman -Sy docker docker-compose --noconfirm
|
echo "Docker installed successfully."
|
||||||
systemctl enable docker.service
|
else
|
||||||
|
echo "Failed to install Docker with apk. Try to install it manually."
|
||||||
|
echo "Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"arch")
|
||||||
|
pacman -Sy docker docker-compose --noconfirm
|
||||||
|
systemctl enable docker.service
|
||||||
|
if [ -x "$(command -v docker)" ]; then
|
||||||
|
echo "Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo "Failed to install Docker with pacman. Try to install it manually."
|
||||||
|
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"amzn")
|
||||||
|
dnf install docker -y
|
||||||
|
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
||||||
|
mkdir -p $DOCKER_CONFIG/cli-plugins
|
||||||
|
curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||||
|
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||||
|
systemctl start docker
|
||||||
|
systemctl enable docker
|
||||||
|
if [ -x "$(command -v docker)" ]; then
|
||||||
|
echo "Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo "Failed to install Docker with dnf. Try to install it manually."
|
||||||
|
echo "Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Automated Docker installation
|
||||||
|
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
||||||
|
if [ -x "$(command -v docker)" ]; then
|
||||||
|
echo "Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo "Docker installation failed with Rancher script. Trying with official script."
|
||||||
|
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
||||||
if [ -x "$(command -v docker)" ]; then
|
if [ -x "$(command -v docker)" ]; then
|
||||||
echo "Docker installed successfully."
|
echo "Docker installed successfully."
|
||||||
else
|
else
|
||||||
echo "Failed to install Docker with pacman. Try to install it manually."
|
echo "Docker installation failed with official script."
|
||||||
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
echo "Maybe your OS is not supported?"
|
||||||
exit
|
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
fi
|
exit 1
|
||||||
else
|
|
||||||
# Amazon Linux 2023
|
|
||||||
if [ "$OS_TYPE" = "amzn" ]; then
|
|
||||||
dnf install docker -y
|
|
||||||
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
|
||||||
mkdir -p $DOCKER_CONFIG/cli-plugins
|
|
||||||
curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose
|
|
||||||
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
|
|
||||||
systemctl start docker
|
|
||||||
systemctl enable docker
|
|
||||||
if [ -x "$(command -v docker)" ]; then
|
|
||||||
echo "Docker installed successfully."
|
|
||||||
else
|
|
||||||
echo "Failed to install Docker with pacman. Try to install it manually."
|
|
||||||
echo "Please visit https://wiki.archlinux.org/title/docker for more information."
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Automated Docker installation
|
|
||||||
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
|
||||||
if [ -x "$(command -v docker)" ]; then
|
|
||||||
echo "Docker installed successfully."
|
|
||||||
else
|
|
||||||
echo "Docker installation failed with Rancher script. Trying with official script."
|
|
||||||
curl https://get.docker.com | sh -s -- --version ${DOCKER_VERSION}
|
|
||||||
if [ -x "$(command -v docker)" ]; then
|
|
||||||
echo "Docker installed successfully."
|
|
||||||
else
|
|
||||||
echo "Docker installation failed with official script."
|
|
||||||
echo "Maybe your OS is not supported?"
|
|
||||||
echo "Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
esac
|
||||||
set -e
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "-------------"
|
echo -e "-------------"
|
||||||
@@ -267,17 +276,50 @@ if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify
|
|||||||
fi
|
fi
|
||||||
mv "$TEMP_FILE" /etc/docker/daemon.json
|
mv "$TEMP_FILE" /etc/docker/daemon.json
|
||||||
|
|
||||||
|
restart_docker_service() {
|
||||||
|
|
||||||
|
# Check if systemctl is available
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo "Using systemctl to restart Docker..."
|
||||||
|
systemctl restart docker
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Docker restarted successfully using systemctl."
|
||||||
|
else
|
||||||
|
echo "Failed to restart Docker using systemctl."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if service command is available
|
||||||
|
elif command -v service >/dev/null 2>&1; then
|
||||||
|
echo "Using service command to restart Docker..."
|
||||||
|
service docker restart
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Docker restarted successfully using service."
|
||||||
|
else
|
||||||
|
echo "Failed to restart Docker using service."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If neither systemctl nor service is available
|
||||||
|
else
|
||||||
|
echo "Neither systemctl nor service command is available on this system."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||||
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
||||||
if [ "$DIFF" != "" ]; then
|
if [ "$DIFF" != "" ]; then
|
||||||
echo "Docker configuration updated, restart docker daemon..."
|
echo "Docker configuration updated, restart docker daemon..."
|
||||||
systemctl restart docker
|
restart_docker_service
|
||||||
else
|
else
|
||||||
echo "Docker configuration is up to date."
|
echo "Docker configuration is up to date."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Docker configuration updated, restart docker daemon..."
|
echo "Docker configuration updated, restart docker daemon..."
|
||||||
systemctl restart docker
|
restart_docker_service
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "-------------"
|
echo -e "-------------"
|
||||||
@@ -296,28 +338,35 @@ curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
|||||||
curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||||
|
|
||||||
# Copy .env.example if .env does not exist
|
# Copy .env.example if .env does not exist
|
||||||
if [ ! -f $ENV_FILE ]; then
|
if [ -f $ENV_FILE ]; then
|
||||||
cp /data/coolify/source/.env.production $ENV_FILE
|
echo "File exists: $ENV_FILE"
|
||||||
# Generate a secure APP_ID and APP_KEY
|
echo "Copying .env to .env-$DATE"
|
||||||
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE"
|
cp $ENV_FILE $ENV_FILE-$DATE
|
||||||
sed -i "s|^APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|" "$ENV_FILE"
|
else
|
||||||
|
echo "File does not exist: $ENV_FILE"
|
||||||
|
echo "Copying .env.production to .env-$DATE"
|
||||||
|
cp /data/coolify/source/.env.production $ENV_FILE-$DATE
|
||||||
|
# Generate a secure APP_ID and APP_KEY
|
||||||
|
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
# Generate a secure Postgres DB username and password
|
# Generate a secure Postgres DB username and password
|
||||||
# Causes issues: database "random-user" does not exist
|
# Causes issues: database "random-user" does not exist
|
||||||
# sed -i "s|^DB_USERNAME=.*|DB_USERNAME=$(openssl rand -hex 16)|" "$ENV_FILE"
|
# sed -i "s|^DB_USERNAME=.*|DB_USERNAME=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||||
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE"
|
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
# Generate a secure Redis password
|
# Generate a secure Redis password
|
||||||
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE"
|
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
# Generate secure Pusher credentials
|
# Generate secure Pusher credentials
|
||||||
sed -i "s|^PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|" "$ENV_FILE"
|
sed -i "s|^PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
sed -i "s|^PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|" "$ENV_FILE"
|
sed -i "s|^PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE"
|
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
echo "Updating .env with new values (if necessary)..."
|
||||||
|
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production > $ENV_FILE
|
||||||
|
|
||||||
if [ "$AUTOUPDATE" = "false" ]; then
|
if [ "$AUTOUPDATE" = "false" ]; then
|
||||||
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||||
@@ -350,9 +399,13 @@ if ! grep -qw "root@coolify" ~/.ssh/authorized_keys; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}"
|
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}"
|
||||||
|
rm -f $ENV_FILE-$DATE
|
||||||
echo "Waiting for 20 seconds for Coolify to be ready..."
|
echo "Waiting for 20 seconds for Coolify to be ready..."
|
||||||
|
|
||||||
sleep 20
|
sleep 20
|
||||||
echo "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started."
|
echo "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started."
|
||||||
echo -e "\nCongratulations! Your Coolify instance is ready to use.\n"
|
echo -e "\nCongratulations! Your Coolify instance is ready to use.\n"
|
||||||
|
|
||||||
|
echo -e "Make sure you backup your /data/coolify/source/.env file to a safe location, outside of this server.\n"
|
||||||
|
cp /data/coolify/source/.env /data/coolify/source/.env.backup
|
||||||
|
echo -e "Your .env file has been copied to /data/coolify/source/.env.backup\n"
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.p
|
|||||||
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||||
|
|
||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
sort -u -t '=' -k 1,1 /data/coolify/source/.env /data/coolify/source/.env.production | sed '/^$/d' >/data/coolify/source/.env.temp && mv /data/coolify/source/.env.temp /data/coolify/source/.env
|
awk -F '=' '!seen[$1]++' /data/coolify/source/.env /data/coolify/source/.env.production > /data/coolify/source/.env.tmp && mv /data/coolify/source/.env.tmp /data/coolify/source/.env
|
||||||
|
|
||||||
# Check if PUSHER_APP_ID or PUSHER_APP_KEY or PUSHER_APP_SECRET is empty in /data/coolify/source/.env
|
# Check if PUSHER_APP_ID or PUSHER_APP_KEY or PUSHER_APP_SECRET is empty in /data/coolify/source/.env
|
||||||
if grep -q "PUSHER_APP_ID=$" /data/coolify/source/.env; then
|
if grep -q "PUSHER_APP_ID=$" /data/coolify/source/.env; then
|
||||||
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
sed -i "s|PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|g" /data/coolify/source/.env
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"coolify": {
|
"coolify": {
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.332"
|
"version": "4.0.0-beta.333"
|
||||||
},
|
},
|
||||||
"nightly": {
|
"nightly": {
|
||||||
"version": "4.0.0-beta.333"
|
"version": "4.0.0-beta.334"
|
||||||
},
|
},
|
||||||
"helper": {
|
"helper": {
|
||||||
"version": "1.0.1"
|
"version": "1.0.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user