diff --git a/README.md b/README.md
index c3412be14..14a741088 100644
--- a/README.md
+++ b/README.md
@@ -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.
* [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.
-* [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.
* [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.
diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php
index f7b54cd80..540085385 100644
--- a/app/Jobs/ServerCheckJob.php
+++ b/app/Jobs/ServerCheckJob.php
@@ -47,12 +47,12 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array
{
- return [(new WithoutOverlapping($this->server->uuid))];
+ return [(new WithoutOverlapping($this->server->id))];
}
public function uniqueId(): int
{
- return $this->server->uuid;
+ return $this->server->id;
}
public function handle()
diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php
index 147a1ad6f..0bfcaf729 100644
--- a/app/Livewire/Boarding/Index.php
+++ b/app/Livewire/Boarding/Index.php
@@ -73,6 +73,8 @@ class Index extends Component
}
$this->privateKeyName = generate_random_name();
$this->remoteServerName = generate_random_name();
+ $this->remoteServerPort = $this->remoteServerPort;
+ $this->remoteServerUser = $this->remoteServerUser;
if (isDev()) {
$this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
@@ -154,6 +156,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
$this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
if ($this->servers->count() > 0) {
$this->selectedExistingServer = $this->servers->first()->id;
+ $this->updateServerDetails();
$this->currentState = 'select-existing-server';
return;
@@ -173,9 +176,18 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
}
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
$this->serverPublicKey = $this->createdServer->privateKey->publicKey();
+ $this->updateServerDetails();
$this->currentState = 'validate-server';
}
+ private function updateServerDetails()
+ {
+ if ($this->createdServer) {
+ $this->remoteServerPort = $this->createdServer->port;
+ $this->remoteServerUser = $this->createdServer->user;
+ }
+ }
+
public function getProxyType()
{
// Set Default Proxy Type
@@ -235,11 +247,12 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
public function saveServer()
{
$this->validate([
- 'remoteServerName' => 'required',
- 'remoteServerHost' => 'required',
+ 'remoteServerName' => 'required|string',
+ 'remoteServerHost' => 'required|string',
'remoteServerPort' => 'required|integer',
- 'remoteServerUser' => 'required',
+ 'remoteServerUser' => 'required|string',
]);
+
$this->privateKey = formatPrivateKey($this->privateKey);
$foundServer = Server::whereIp($this->remoteServerHost)->first();
if ($foundServer) {
@@ -277,9 +290,12 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
$this->createdServer->settings()->update([
'is_reachable' => true,
]);
+ $this->serverReachable = true;
} catch (\Throwable $e) {
$this->serverReachable = false;
- $this->createdServer->delete();
+ $this->createdServer->settings()->update([
+ 'is_reachable' => false,
+ ]);
return handleError(error: $e, livewire: $this);
}
@@ -296,6 +312,10 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
]);
$this->getProxyType();
} catch (\Throwable $e) {
+ $this->createdServer->settings()->update([
+ 'is_usable' => false,
+ ]);
+
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()
{
$this->privateKeyName = generate_random_name();
diff --git a/app/Models/Server.php b/app/Models/Server.php
index c72c7cc95..46536ed47 100644
--- a/app/Models/Server.php
+++ b/app/Models/Server.php
@@ -112,6 +112,16 @@ class Server extends BaseModel
'proxy',
];
+ protected $fillable = [
+ 'name',
+ 'ip',
+ 'port',
+ 'user',
+ 'description',
+ 'private_key_id',
+ 'team_id',
+ ];
+
protected $guarded = [];
public static function isReachable()
diff --git a/bootstrap/helpers/constants.php b/bootstrap/helpers/constants.php
index f94c9bc20..1eeec8f94 100644
--- a/bootstrap/helpers/constants.php
+++ b/bootstrap/helpers/constants.php
@@ -46,6 +46,7 @@ const SUPPORTED_OS = [
'centos fedora rhel ol rocky amzn almalinux',
'sles opensuse-leap opensuse-tumbleweed',
'arch',
+ 'alpine',
];
const SHARED_VARIABLE_TYPES = ['team', 'project', 'environment'];
diff --git a/config/sentry.php b/config/sentry.php
index a978caa5e..eb0a3a508 100644
--- a/config/sentry.php
+++ b/config/sentry.php
@@ -7,7 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
- 'release' => '4.0.0-beta.332',
+ 'release' => '4.0.0-beta.333',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),
diff --git a/config/version.php b/config/version.php
index cb4452172..c3c14e32b 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@
/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)
apt-get update -y >/dev/null
apt-get install -y curl wget git jq >/dev/null
@@ -172,70 +177,74 @@ if [ -x "$(command -v snap)" ]; then
fi
if ! [ -x "$(command -v docker)" ]; then
- # Almalinux
- if [ "$OS_TYPE" == 'almalinux' ]; then
- 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
- 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."
- exit 1
- fi
- systemctl start docker
- systemctl enable docker
- else
- set +e
- if ! [ -x "$(command -v docker)" ]; then
- echo "Docker is not installed. Installing Docker."
- # Arch Linux
- if [ "$OS_TYPE" = "arch" ]; then
- pacman -Sy docker docker-compose --noconfirm
- systemctl enable docker.service
+ case "$OS_TYPE" in
+ "almalinux")
+ 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
+ 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."
+ exit 1
+ fi
+ systemctl start 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
+ 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
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
- # 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
+ 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
- set -e
- fi
+ esac
fi
echo -e "-------------"
@@ -267,17 +276,50 @@ if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify
fi
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
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
if [ "$DIFF" != "" ]; then
echo "Docker configuration updated, restart docker daemon..."
- systemctl restart docker
+ restart_docker_service
else
echo "Docker configuration is up to date."
fi
else
echo "Docker configuration updated, restart docker daemon..."
- systemctl restart docker
+ restart_docker_service
fi
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
# Copy .env.example if .env does not exist
-if [ ! -f $ENV_FILE ]; then
- cp /data/coolify/source/.env.production $ENV_FILE
- # 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_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|" "$ENV_FILE"
+if [ -f $ENV_FILE ]; then
+ 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
+ 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
# 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_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|" "$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-$DATE"
# 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
- sed -i "s|^PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|" "$ENV_FILE"
- sed -i "s|^PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|" "$ENV_FILE"
- sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(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-$DATE"
+ sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
fi
# 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 ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
@@ -350,7 +399,7 @@ if ! grep -qw "root@coolify" ~/.ssh/authorized_keys; then
fi
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..."
sleep 20
diff --git a/other/nightly/upgrade.sh b/other/nightly/upgrade.sh
index bce82aaa5..45295a510 100644
--- a/other/nightly/upgrade.sh
+++ b/other/nightly/upgrade.sh
@@ -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
# 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
if grep -q "PUSHER_APP_ID=$" /data/coolify/source/.env; then
diff --git a/resources/views/livewire/boarding/index.blade.php b/resources/views/livewire/boarding/index.blade.php
index 2e5fa41c9..7b7ef8c12 100644
--- a/resources/views/livewire/boarding/index.blade.php
+++ b/resources/views/livewire/boarding/index.blade.php
@@ -28,25 +28,33 @@
+
+
+
Please check the connection details below and correct them if they are + incorrect.
+ ++ Non-root user is experimental: + docs +
+If the connection details are correct, please ensure:
+~/.ssh/authorized_keys
+ file for the specified user+ For more help, check this documentation. +
+ +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 are deploying your resources.
-
+
+
Please check the connection details below and correct them if they are + incorrect.
+ ++ Non-root user is experimental: + docs +
+If the connection details are correct, please ensure:
+~/.ssh/authorized_keys
+ file for the specified user+ For more help, check this documentation. +
+ +