Merge pull request #3389 from coollabsio/next

v4.0.0-beta.333
This commit is contained in:
Andras Bacsai
2024-09-11 14:26:58 +02:00
committed by GitHub
13 changed files with 449 additions and 226 deletions

View File

@@ -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.

View File

@@ -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()

View File

@@ -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();

View File

@@ -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()

View File

@@ -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'];

View File

@@ -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'),

View File

@@ -1,3 +1,3 @@
<?php <?php
return '4.0.0-beta.332'; return '4.0.0-beta.333';

View File

@@ -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,8 +177,8 @@ 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
@@ -182,12 +187,20 @@ if ! [ -x "$(command -v docker)" ]; then
fi fi
systemctl start docker systemctl start docker
systemctl enable docker systemctl enable docker
;;
"alpine")
apk add docker docker-cli-compose
rc-update add docker default
service docker start
if [ -x "$(command -v docker)" ]; then
echo "Docker installed successfully."
else else
set +e echo "Failed to install Docker with apk. Try to install it manually."
if ! [ -x "$(command -v docker)" ]; then echo "Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
echo "Docker is not installed. Installing Docker." exit
# Arch Linux fi
if [ "$OS_TYPE" = "arch" ]; then ;;
"arch")
pacman -Sy docker docker-compose --noconfirm pacman -Sy docker docker-compose --noconfirm
systemctl enable docker.service systemctl enable docker.service
if [ -x "$(command -v docker)" ]; then if [ -x "$(command -v docker)" ]; then
@@ -197,9 +210,8 @@ if ! [ -x "$(command -v docker)" ]; then
echo "Please visit https://wiki.archlinux.org/title/docker for more information." echo "Please visit https://wiki.archlinux.org/title/docker for more information."
exit exit
fi fi
else ;;
# Amazon Linux 2023 "amzn")
if [ "$OS_TYPE" = "amzn" ]; then
dnf install docker -y dnf install docker -y
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker} DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
mkdir -p $DOCKER_CONFIG/cli-plugins mkdir -p $DOCKER_CONFIG/cli-plugins
@@ -210,11 +222,12 @@ if ! [ -x "$(command -v docker)" ]; then
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 "Failed to install Docker with dnf. Try to install it manually."
echo "Please visit https://wiki.archlinux.org/title/docker for more information." echo "Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
exit exit
fi fi
else ;;
*)
# Automated Docker installation # Automated Docker installation
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
if [ -x "$(command -v docker)" ]; then if [ -x "$(command -v docker)" ]; then
@@ -231,11 +244,7 @@ if ! [ -x "$(command -v docker)" ]; then
exit 1 exit 1
fi fi
fi fi
fi esac
fi
fi
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"
cat $ENV_FILE
echo "Copying .env to .env-$DATE"
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 # Generate a secure APP_ID and APP_KEY
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE" 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" 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

View File

@@ -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

View File

@@ -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">
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> </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:
<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> </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 x-data="{ showAdvanced: false }" class="flex flex-col gap-2">
<button @click="showAdvanced = !showAdvanced" type="button"
class="text-left text-sm text-gray-600 dark:text-gray-300 hover:underline">
Advanced Settings
</button>
<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"> <div class="w-full">
<x-forms.input required placeholder="User to connect to your server. Default is root." <x-forms.input placeholder="Default is root." label="User"
label="User" id="remoteServerUser" /> id="remoteServerUser" wire:model="remoteServerUser" />
<div class="text-xs dark:text-warning text-coollabs ">Non-root user is experimental: <a <div class="text-xs text-gray-600 dark:text-gray-300">Non-root user is
class="font-bold underline" target="_blank" experimental: <a class="font-bold underline" target="_blank"
href="https://coolify.io/docs/knowledge-base/server/non-root-user">docs</a>. 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>

View File

@@ -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,8 +177,8 @@ 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
@@ -182,12 +187,20 @@ if ! [ -x "$(command -v docker)" ]; then
fi fi
systemctl start docker systemctl start docker
systemctl enable docker systemctl enable docker
;;
"alpine")
apk add docker docker-cli-compose
rc-update add docker default
service docker start
if [ -x "$(command -v docker)" ]; then
echo "Docker installed successfully."
else else
set +e echo "Failed to install Docker with apk. Try to install it manually."
if ! [ -x "$(command -v docker)" ]; then echo "Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
echo "Docker is not installed. Installing Docker." exit
# Arch Linux fi
if [ "$OS_TYPE" = "arch" ]; then ;;
"arch")
pacman -Sy docker docker-compose --noconfirm pacman -Sy docker docker-compose --noconfirm
systemctl enable docker.service systemctl enable docker.service
if [ -x "$(command -v docker)" ]; then if [ -x "$(command -v docker)" ]; then
@@ -197,9 +210,8 @@ if ! [ -x "$(command -v docker)" ]; then
echo "Please visit https://wiki.archlinux.org/title/docker for more information." echo "Please visit https://wiki.archlinux.org/title/docker for more information."
exit exit
fi fi
else ;;
# Amazon Linux 2023 "amzn")
if [ "$OS_TYPE" = "amzn" ]; then
dnf install docker -y dnf install docker -y
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker} DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
mkdir -p $DOCKER_CONFIG/cli-plugins mkdir -p $DOCKER_CONFIG/cli-plugins
@@ -210,11 +222,12 @@ if ! [ -x "$(command -v docker)" ]; then
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 "Failed to install Docker with dnf. Try to install it manually."
echo "Please visit https://wiki.archlinux.org/title/docker for more information." echo "Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
exit exit
fi fi
else ;;
*)
# Automated Docker installation # Automated Docker installation
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
if [ -x "$(command -v docker)" ]; then if [ -x "$(command -v docker)" ]; then
@@ -231,11 +244,7 @@ if ! [ -x "$(command -v docker)" ]; then
exit 1 exit 1
fi fi
fi fi
fi esac
fi
fi
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"
echo "Copying .env to .env-$DATE"
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 # Generate a secure APP_ID and APP_KEY
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE" 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" 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"

View File

@@ -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

View File

@@ -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"