diff --git a/.dockerignore b/.dockerignore
index 6f3c903f0f..aba2137d0e 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -23,7 +23,7 @@ yarn-error.log
/.ssh
.ignition.json
.env.dusk.local
-docker/coolify-realtime/node_modules
+docker/coolify-terminal/node_modules
/storage/*.key
/storage/app/backups
diff --git a/.env.production b/.env.production
index cda3214d2d..c6990a51d4 100644
--- a/.env.production
+++ b/.env.production
@@ -10,7 +10,6 @@ REDIS_PASSWORD=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
-
ROOT_USERNAME=
ROOT_USER_EMAIL=
ROOT_USER_PASSWORD=
diff --git a/.env.windows-docker-desktop.example b/.env.windows-docker-desktop.example
index b067b4c5c0..e97249505d 100644
--- a/.env.windows-docker-desktop.example
+++ b/.env.windows-docker-desktop.example
@@ -11,3 +11,4 @@ REDIS_PASSWORD=coolify
PUSHER_APP_ID=coolify
PUSHER_APP_KEY=coolify
PUSHER_APP_SECRET=coolify
+PUSHER_BACKEND_PORT=6001
diff --git a/.github/workflows/cleanup-ghcr-untagged.yml b/.github/workflows/cleanup-ghcr-untagged.yml
index a86cedcb03..b6dc7618d2 100644
--- a/.github/workflows/cleanup-ghcr-untagged.yml
+++ b/.github/workflows/cleanup-ghcr-untagged.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- package: ['coolify', 'coolify-helper', 'coolify-realtime', 'coolify-testing-host']
+ package: ['coolify', 'coolify-helper', 'coolify-testing-host']
steps:
- name: Delete untagged ${{ matrix.package }} images
uses: actions/delete-package-versions@v5
diff --git a/.github/workflows/coolify-realtime-next.yml b/.github/workflows/coolify-realtime-next.yml
deleted file mode 100644
index 8937ea27dd..0000000000
--- a/.github/workflows/coolify-realtime-next.yml
+++ /dev/null
@@ -1,120 +0,0 @@
-name: Coolify Realtime Development
-
-on:
- push:
- branches: [ "next" ]
- paths:
- - .github/workflows/coolify-realtime-next.yml
- - docker/coolify-realtime/Dockerfile
- - docker/coolify-realtime/terminal-server.js
- - docker/coolify-realtime/package.json
- - docker/coolify-realtime/package-lock.json
- - docker/coolify-realtime/soketi-entrypoint.sh
-
-permissions:
- contents: read
- packages: write
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify-realtime"
-
-jobs:
- build-push:
- strategy:
- matrix:
- include:
- - arch: amd64
- platform: linux/amd64
- runner: ubuntu-24.04
- - arch: aarch64
- platform: linux/aarch64
- runner: ubuntu-24.04-arm
- runs-on: ${{ matrix.runner }}
- steps:
- - uses: actions/checkout@v5
- with:
- persist-credentials: false
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image (${{ matrix.arch }})
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-realtime/Dockerfile
- platforms: ${{ matrix.platform }}
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-${{ matrix.arch }}
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-${{ matrix.arch }}
- labels: |
- coolify.managed=true
-
- merge-manifest:
- runs-on: ubuntu-24.04
- needs: build-push
- steps:
- - uses: actions/checkout@v5
- with:
- persist-credentials: false
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-amd64 \
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:next
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-amd64 \
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-next \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:next
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_RELEASE_CHANNEL }}
diff --git a/.github/workflows/coolify-realtime.yml b/.github/workflows/coolify-realtime.yml
deleted file mode 100644
index 495e6a4637..0000000000
--- a/.github/workflows/coolify-realtime.yml
+++ /dev/null
@@ -1,163 +0,0 @@
-name: Coolify Realtime
-
-on:
- workflow_dispatch:
- push:
- branches: [ "main" ]
- paths:
- - .github/workflows/coolify-realtime.yml
- - config/constants.php
- - docker/coolify-realtime/**
-
-permissions:
- contents: read
- packages: write
-
-env:
- GITHUB_REGISTRY: ghcr.io
- DOCKER_REGISTRY: docker.io
- IMAGE_NAME: "coollabsio/coolify-realtime"
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: false
-
-jobs:
- check-version:
- runs-on: ubuntu-24.04
- steps:
- - uses: actions/checkout@v5
- with:
- persist-credentials: false
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Ensure version is not published
- run: |
- BASE_VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)
- VERSION="${BASE_VERSION}"
- for registry in "${DOCKER_REGISTRY}" "${GITHUB_REGISTRY}"; do
- IMAGE="${registry}/${IMAGE_NAME}:${VERSION}"
- if output=$(docker buildx imagetools inspect "$IMAGE" 2>&1); then
- echo "::error::Version $VERSION already exists in $registry"
- exit 1
- fi
- if ! grep -Eqi 'manifest unknown|not found|no such manifest' <<< "$output"; then
- echo "::error::Could not verify $IMAGE: $output"
- exit 1
- fi
- done
- echo "Version $VERSION is available in both registries"
-
- build-push:
- needs: check-version
- strategy:
- matrix:
- include:
- - arch: amd64
- platform: linux/amd64
- runner: ubuntu-24.04
- - arch: aarch64
- platform: linux/aarch64
- runner: ubuntu-24.04-arm
- runs-on: ${{ matrix.runner }}
- steps:
- - uses: actions/checkout@v5
- with:
- persist-credentials: false
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Build and Push Image (${{ matrix.arch }})
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/coolify-realtime/Dockerfile
- platforms: ${{ matrix.platform }}
- push: true
- tags: |
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-${{ matrix.arch }}
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-${{ matrix.arch }}
- labels: |
- coolify.managed=true
-
- merge-manifest:
- runs-on: ubuntu-24.04
- needs: build-push
- steps:
- - uses: actions/checkout@v5
- with:
- persist-credentials: false
-
- - uses: docker/setup-buildx-action@v3
-
- - name: Login to ${{ env.GITHUB_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.GITHUB_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Login to ${{ env.DOCKER_REGISTRY }}
- uses: docker/login-action@v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Get Version
- id: version
- run: |
- echo "VERSION=$(docker run --rm -v "$(pwd):/app" -w /app php:8.2-alpine3.16 php bootstrap/getRealtimeVersion.php)"|xargs >> $GITHUB_OUTPUT
-
- - name: Create & publish manifest on ${{ env.GITHUB_REGISTRY }}
- run: |
- docker buildx imagetools create \
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-amd64 \
- ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \
- --tag ${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - name: Create & publish manifest on ${{ env.DOCKER_REGISTRY }}
- run: |
- docker buildx imagetools create \
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-amd64 \
- ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64 \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \
- --tag ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
- - uses: sarisia/actions-status-discord@v1
- if: always()
- with:
- webhook: ${{ secrets.DISCORD_WEBHOOK_PROD_RELEASE_CHANNEL }}
diff --git a/.github/workflows/generate-changelog.yml b/.github/workflows/generate-changelog.yml
index 6e88c0d600..a9878e7c41 100644
--- a/.github/workflows/generate-changelog.yml
+++ b/.github/workflows/generate-changelog.yml
@@ -6,8 +6,6 @@ on:
paths-ignore:
- .github/workflows/coolify-helper.yml
- .github/workflows/coolify-helper-next.yml
- - .github/workflows/coolify-realtime.yml
- - .github/workflows/coolify-realtime-next.yml
- .github/workflows/pr-quality.yaml
workflow_dispatch:
diff --git a/.gitignore b/.gitignore
index efba1ec76d..3b583795bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,7 +34,7 @@ _ide_helper_models.php
scripts/load-test/*
.ignition.json
.env.dusk.local
-docker/coolify-realtime/node_modules
+docker/coolify-terminal/node_modules
.DS_Store
CHANGELOG.md
/.workspaces
diff --git a/app/Actions/Server/CleanupDocker.php b/app/Actions/Server/CleanupDocker.php
index 04fe00ad48..9f58fd4f88 100644
--- a/app/Actions/Server/CleanupDocker.php
+++ b/app/Actions/Server/CleanupDocker.php
@@ -13,12 +13,6 @@ class CleanupDocker
public function handle(Server $server, bool $deleteUnusedVolumes = false, bool $deleteUnusedNetworks = false)
{
- $realtimeImage = config('constants.coolify.realtime_image');
- $realtimeImageVersion = config('constants.coolify.realtime_version');
- $realtimeImageWithVersion = "$realtimeImage:$realtimeImageVersion";
- $realtimeImageWithoutPrefix = 'coollabsio/coolify-realtime';
- $realtimeImageWithoutPrefixVersion = "coollabsio/coolify-realtime:$realtimeImageVersion";
-
$helperImageVersion = getHelperVersion();
$helperImage = coolifyHelperImage();
$helperImageWithVersion = "$helperImage:$helperImageVersion";
@@ -41,13 +35,12 @@ class CleanupDocker
$cleanupLog = array_merge($cleanupLog, $applicationCleanupLog);
// Build image prune command that excludes application images and current Coolify infrastructure images
- // This ensures we clean up non-Coolify images while preserving rollback images and current helper/realtime images
+ // This ensures we clean up non-Coolify images while preserving rollback images and current helper image
// Note: Only the current version is protected; old versions will be cleaned up by explicit commands below
// We pass the version strings so all registry variants are protected (ghcr.io, docker.io, no prefix)
$imagePruneCmd = $this->buildImagePruneCommand(
$applicationImageRepos,
- $helperImageVersion,
- $realtimeImageVersion
+ $helperImageVersion
);
$commands = [
@@ -56,9 +49,7 @@ class CleanupDocker
'docker builder prune -af',
"docker run --rm -v {$buildxMetadataVolume}:/root/.docker/buildx -v /var/run/docker.sock:/var/run/docker.sock {$helperImageWithVersion} docker buildx prune --builder coolify-railpack -af 2>/dev/null || true",
"docker images --filter before=$helperImageWithVersion --filter reference=$helperImage | grep $helperImage | awk '{print $3}' | xargs -r docker rmi -f",
- "docker images --filter before=$realtimeImageWithVersion --filter reference=$realtimeImage | grep $realtimeImage | awk '{print $3}' | xargs -r docker rmi -f",
"docker images --filter before=$helperImageWithoutPrefixVersion --filter reference=$helperImageWithoutPrefix | grep $helperImageWithoutPrefix | awk '{print $3}' | xargs -r docker rmi -f",
- "docker images --filter before=$realtimeImageWithoutPrefixVersion --filter reference=$realtimeImageWithoutPrefix | grep $realtimeImageWithoutPrefix | awk '{print $3}' | xargs -r docker rmi -f",
];
if ($deleteUnusedVolumes) {
@@ -90,8 +81,7 @@ class CleanupDocker
*/
private function buildImagePruneCommand(
$applicationImageRepos,
- string $helperImageVersion,
- string $realtimeImageVersion
+ string $helperImageVersion
): string {
// Step 1: Always prune dangling images (untagged)
$commands = ['docker image prune -f'];
@@ -108,14 +98,13 @@ class CleanupDocker
// - ghcr.io/coollabsio/coolify-helper:1.0.12
// - docker.io/coollabsio/coolify-helper:1.0.12
// - coollabsio/coolify-helper:1.0.12
- // Pattern: (^|/)coollabsio/coolify-(helper|realtime):VERSION$
+ // Pattern: (^|/)coollabsio/coolify-helper:VERSION$
$escapedHelperVersion = preg_replace('/([.\\\\+*?\[\]^$(){}|])/', '\\\\$1', $helperImageVersion);
- $escapedRealtimeVersion = preg_replace('/([.\\\\+*?\[\]^$(){}|])/', '\\\\$1', $realtimeImageVersion);
- $infraExcludePattern = "(^|/)coollabsio/coolify-helper:{$escapedHelperVersion}$|(^|/)coollabsio/coolify-realtime:{$escapedRealtimeVersion}$";
+ $infraExcludePattern = "(^|/)coollabsio/coolify-helper:{$escapedHelperVersion}$";
// Delete unused images that:
// - Are not application images (don't match app repos)
- // - Are not current Coolify infrastructure images (any registry)
+ // - Are not current Coolify helper image (any registry)
// - Don't have coolify.managed=true label
// Images in use by containers will fail silently with docker rmi
// Pattern matches both uuid:tag and uuid_servicename:tag (Docker Compose with build)
diff --git a/app/Models/Server.php b/app/Models/Server.php
index 7a9269d4c7..20952d5598 100644
--- a/app/Models/Server.php
+++ b/app/Models/Server.php
@@ -692,13 +692,20 @@ class Server extends BaseModel
'service' => 'coolify',
'rule' => "Host(`{$host}`)",
],
- 'coolify-realtime-ws' => [
+ 'coolify-reverb-ws' => [
'entryPoints' => [
0 => 'http',
],
- 'service' => 'coolify-realtime',
+ 'service' => 'coolify-reverb',
'rule' => "Host(`{$host}`) && PathPrefix(`/app`)",
],
+ 'coolify-reverb-api' => [
+ 'entryPoints' => [
+ 0 => 'http',
+ ],
+ 'service' => 'coolify-reverb',
+ 'rule' => "Host(`{$host}`) && PathPrefix(`/apps`)",
+ ],
'coolify-terminal-ws' => [
'entryPoints' => [
0 => 'http',
@@ -717,11 +724,11 @@ class Server extends BaseModel
],
],
],
- 'coolify-realtime' => [
+ 'coolify-reverb' => [
'loadBalancer' => [
'servers' => [
0 => [
- 'url' => 'http://coolify-realtime:6001',
+ 'url' => 'http://coolify:6001',
],
],
],
@@ -730,7 +737,7 @@ class Server extends BaseModel
'loadBalancer' => [
'servers' => [
0 => [
- 'url' => 'http://coolify-realtime:6002',
+ 'url' => 'http://coolify:6002',
],
],
],
@@ -755,16 +762,26 @@ class Server extends BaseModel
'certresolver' => 'letsencrypt',
],
];
- $traefik_dynamic_conf['http']['routers']['coolify-realtime-wss'] = [
+ $traefik_dynamic_conf['http']['routers']['coolify-reverb-wss'] = [
'entryPoints' => [
0 => 'https',
],
- 'service' => 'coolify-realtime',
+ 'service' => 'coolify-reverb',
'rule' => "Host(`{$host}`) && PathPrefix(`/app`)",
'tls' => [
'certresolver' => 'letsencrypt',
],
];
+ $traefik_dynamic_conf['http']['routers']['coolify-reverb-api-https'] = [
+ 'entryPoints' => [
+ 0 => 'https',
+ ],
+ 'service' => 'coolify-reverb',
+ 'rule' => "Host(`{$host}`) && PathPrefix(`/apps`)",
+ 'tls' => [
+ 'certresolver' => 'letsencrypt',
+ ],
+ ];
$traefik_dynamic_conf['http']['routers']['coolify-terminal-wss'] = [
'entryPoints' => [
0 => 'https',
@@ -804,10 +821,13 @@ class Server extends BaseModel
$siteAddress {
encode zstd gzip
handle /app/* {
- reverse_proxy coolify-realtime:6001
+ reverse_proxy coolify:6001
+ }
+ handle /apps* {
+ reverse_proxy coolify:6001
}
handle /terminal/ws {
- reverse_proxy coolify-realtime:6002
+ reverse_proxy coolify:6002
}
reverse_proxy coolify:8080
}";
diff --git a/bootstrap/getRealtimeVersion.php b/bootstrap/getRealtimeVersion.php
deleted file mode 100644
index 1af56f09e5..0000000000
--- a/bootstrap/getRealtimeVersion.php
+++ /dev/null
@@ -1,10 +0,0 @@
-=5.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\Redis\\Protocol\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "description": "A streaming Redis protocol (RESP) parser and serializer written in pure PHP.",
+ "homepage": "https://github.com/clue/redis-protocol",
+ "keywords": [
+ "parser",
+ "protocol",
+ "redis",
+ "resp",
+ "serializer",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/redis-protocol/issues",
+ "source": "https://github.com/clue/redis-protocol/tree/v0.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2024-08-07T11:06:28+00:00"
+ },
+ {
+ "name": "clue/redis-react",
+ "version": "v2.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-redis.git",
+ "reference": "84569198dfd5564977d2ae6a32de4beb5a24bdca"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-redis/zipball/84569198dfd5564977d2ae6a32de4beb5a24bdca",
+ "reference": "84569198dfd5564977d2ae6a32de4beb5a24bdca",
+ "shasum": ""
+ },
+ "require": {
+ "clue/redis-protocol": "^0.3.2",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.0 || ^1.1",
+ "react/promise-timer": "^1.11",
+ "react/socket": "^1.16"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Redis\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async Redis client implementation, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-redis",
+ "keywords": [
+ "async",
+ "client",
+ "database",
+ "reactphp",
+ "redis"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-redis/issues",
+ "source": "https://github.com/clue/reactphp-redis/tree/v2.8.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2025-01-03T16:18:33+00:00"
+ },
{
"name": "danharrin/livewire-rate-limiting",
"version": "v2.2.1",
@@ -972,6 +1102,53 @@
],
"time": "2025-03-06T22:45:56+00:00"
},
+ {
+ "name": "evenement/evenement",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9 || ^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Evenement\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ }
+ ],
+ "description": "Événement is a very simple event dispatching library for PHP",
+ "keywords": [
+ "event-dispatcher",
+ "event-emitter"
+ ],
+ "support": {
+ "issues": "https://github.com/igorw/evenement/issues",
+ "source": "https://github.com/igorw/evenement/tree/v3.0.2"
+ },
+ "time": "2023-08-08T05:53:35+00:00"
+ },
{
"name": "ezyang/htmlpurifier",
"version": "v4.19.0",
@@ -2449,6 +2626,85 @@
},
"time": "2026-08-04T14:50:50+00:00"
},
+ {
+ "name": "laravel/reverb",
+ "version": "v1.11.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laravel/reverb.git",
+ "reference": "52ce5fd88cd1d7eacfdcf6b91cea4704cc546f27"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laravel/reverb/zipball/52ce5fd88cd1d7eacfdcf6b91cea4704cc546f27",
+ "reference": "52ce5fd88cd1d7eacfdcf6b91cea4704cc546f27",
+ "shasum": ""
+ },
+ "require": {
+ "clue/redis-react": "^2.6",
+ "guzzlehttp/psr7": "^2.6",
+ "illuminate/console": "^10.47|^11.0|^12.0|^13.0",
+ "illuminate/contracts": "^10.47|^11.0|^12.0|^13.0",
+ "illuminate/http": "^10.47|^11.0|^12.0|^13.0",
+ "illuminate/support": "^10.47|^11.0|^12.0|^13.0",
+ "laravel/prompts": "^0.1.15|^0.2.0|^0.3.0",
+ "php": "^8.2",
+ "pusher/pusher-php-server": "^7.2",
+ "ratchet/rfc6455": "^0.4",
+ "react/promise-timer": "^1.10",
+ "react/socket": "^1.14",
+ "symfony/console": "^6.0|^7.0|^8.0",
+ "symfony/http-foundation": "^6.3|^7.0|^8.0"
+ },
+ "require-dev": {
+ "orchestra/testbench": "^8.36|^9.15|^10.8|^11.0",
+ "pestphp/pest": "^2.0|^3.0|^4.0",
+ "phpstan/phpstan": "^1.10",
+ "ratchet/pawl": "^0.4.1",
+ "react/async": "^4.2",
+ "react/http": "^1.9"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Laravel\\Reverb\\ApplicationManagerServiceProvider",
+ "Laravel\\Reverb\\ReverbServiceProvider"
+ ]
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Laravel\\Reverb\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ },
+ {
+ "name": "Joe Dixon",
+ "email": "joe@laravel.com"
+ }
+ ],
+ "description": "Laravel Reverb provides a real-time WebSocket communication backend for Laravel applications.",
+ "keywords": [
+ "WebSockets",
+ "laravel",
+ "real-time",
+ "websocket"
+ ],
+ "support": {
+ "issues": "https://github.com/laravel/reverb/issues",
+ "source": "https://github.com/laravel/reverb/tree/v1.11.1"
+ },
+ "time": "2026-08-06T14:48:58+00:00"
+ },
{
"name": "laravel/sanctum",
"version": "v4.3.3",
@@ -6176,6 +6432,595 @@
},
"time": "2026-06-18T03:57:49+00:00"
},
+ {
+ "name": "ratchet/rfc6455",
+ "version": "v0.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ratchetphp/RFC6455.git",
+ "reference": "9b05f371219cbaf9748b505f139617dd0715592b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/9b05f371219cbaf9748b505f139617dd0715592b",
+ "reference": "9b05f371219cbaf9748b505f139617dd0715592b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4",
+ "psr/http-factory-implementation": "^1.0",
+ "symfony/polyfill-php80": "^1.15"
+ },
+ "require-dev": {
+ "guzzlehttp/psr7": "^2.7",
+ "phpunit/phpunit": "^9.5",
+ "react/socket": "^1.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Ratchet\\RFC6455\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Matt Bonneau",
+ "role": "Developer"
+ }
+ ],
+ "description": "RFC6455 WebSocket protocol handler",
+ "homepage": "http://socketo.me",
+ "keywords": [
+ "WebSockets",
+ "rfc6455",
+ "websocket"
+ ],
+ "support": {
+ "chat": "https://gitter.im/reactphp/reactphp",
+ "issues": "https://github.com/ratchetphp/RFC6455/issues",
+ "source": "https://github.com/ratchetphp/RFC6455/tree/v0.4.1"
+ },
+ "time": "2026-06-06T14:34:23+00:00"
+ },
+ {
+ "name": "react/cache",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/cache.git",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/promise": "^3.0 || ^2.0 || ^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, Promise-based cache interface for ReactPHP",
+ "keywords": [
+ "cache",
+ "caching",
+ "promise",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/cache/issues",
+ "source": "https://github.com/reactphp/cache/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2022-11-30T15:59:55+00:00"
+ },
+ {
+ "name": "react/dns",
+ "version": "v1.14.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/dns.git",
+ "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3",
+ "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.7 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4.3 || ^3 || ^2",
+ "react/promise-timer": "^1.11"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Dns\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async DNS resolver for ReactPHP",
+ "keywords": [
+ "async",
+ "dns",
+ "dns-resolver",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/dns/issues",
+ "source": "https://github.com/reactphp/dns/tree/v1.14.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-11-18T19:34:28+00:00"
+ },
+ {
+ "name": "react/event-loop",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/event-loop.git",
+ "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a",
+ "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "suggest": {
+ "ext-pcntl": "For signal handling support when using the StreamSelectLoop"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\EventLoop\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
+ "keywords": [
+ "asynchronous",
+ "event-loop"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/event-loop/issues",
+ "source": "https://github.com/reactphp/event-loop/tree/v1.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-11-17T20:46:25+00:00"
+ },
+ {
+ "name": "react/promise",
+ "version": "v3.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "23444f53a813a3296c1368bb104793ce8d88f04a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a",
+ "reference": "23444f53a813a3296c1368bb104793ce8d88f04a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "1.12.28 || 1.4.10",
+ "phpunit/phpunit": "^9.6 || ^7.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise/issues",
+ "source": "https://github.com/reactphp/promise/tree/v3.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-08-19T18:57:03+00:00"
+ },
+ {
+ "name": "react/promise-timer",
+ "version": "v1.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise-timer.git",
+ "reference": "4f70306ed66b8b44768941ca7f142092600fafc1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/4f70306ed66b8b44768941ca7f142092600fafc1",
+ "reference": "4f70306ed66b8b44768941ca7f142092600fafc1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.7.0 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\Timer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
+ "homepage": "https://github.com/reactphp/promise-timer",
+ "keywords": [
+ "async",
+ "event-loop",
+ "promise",
+ "reactphp",
+ "timeout",
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise-timer/issues",
+ "source": "https://github.com/reactphp/promise-timer/tree/v1.11.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2024-06-04T14:27:45+00:00"
+ },
+ {
+ "name": "react/socket",
+ "version": "v1.17.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/socket.git",
+ "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08",
+ "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/dns": "^1.13",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.2 || ^2.6 || ^1.2.1",
+ "react/stream": "^1.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4.3 || ^3.3 || ^2",
+ "react/promise-stream": "^1.4",
+ "react/promise-timer": "^1.11"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Socket\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
+ "keywords": [
+ "Connection",
+ "Socket",
+ "async",
+ "reactphp",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/socket/issues",
+ "source": "https://github.com/reactphp/socket/tree/v1.17.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2025-11-19T20:47:34+00:00"
+ },
+ {
+ "name": "react/stream",
+ "version": "v1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/stream.git",
+ "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d",
+ "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.2"
+ },
+ "require-dev": {
+ "clue/stream-filter": "~1.2",
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Stream\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
+ "keywords": [
+ "event-driven",
+ "io",
+ "non-blocking",
+ "pipe",
+ "reactphp",
+ "readable",
+ "stream",
+ "writable"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/stream/issues",
+ "source": "https://github.com/reactphp/stream/tree/v1.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2024-06-11T12:45:25+00:00"
+ },
{
"name": "resend/resend-laravel",
"version": "v0.20.0",
diff --git a/config/broadcasting.php b/config/broadcasting.php
index 5509b00730..8348c1a052 100644
--- a/config/broadcasting.php
+++ b/config/broadcasting.php
@@ -11,11 +11,11 @@ return [
| framework when an event needs to be broadcast. You may set this to
| any of the connections defined in the "connections" array below.
|
- | Supported: "pusher", "ably", "redis", "log", "null"
+ | Supported: "reverb", "pusher", "ably", "redis", "log", "null"
|
*/
- 'default' => env('BROADCAST_DRIVER', 'pusher'),
+ 'default' => env('BROADCAST_CONNECTION', env('BROADCAST_DRIVER', 'reverb')),
/*
|--------------------------------------------------------------------------
@@ -30,15 +30,33 @@ return [
'connections' => [
+ 'reverb' => [
+ 'driver' => 'reverb',
+ 'key' => env('PUSHER_APP_KEY', 'coolify'),
+ 'secret' => env('PUSHER_APP_SECRET', 'coolify'),
+ 'app_id' => env('PUSHER_APP_ID', 'coolify'),
+ 'options' => [
+ 'host' => env('PUSHER_HOST', 'coolify'),
+ 'port' => env('PUSHER_BACKEND_PORT', 6001),
+ 'scheme' => env('PUSHER_SCHEME', 'http'),
+ 'encrypted' => true,
+ 'useTLS' => env('PUSHER_SCHEME', 'http') === 'https',
+ 'path' => '',
+ ],
+ 'client_options' => [
+ // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
+ ],
+ ],
+
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY', 'coolify'),
'secret' => env('PUSHER_APP_SECRET', 'coolify'),
'app_id' => env('PUSHER_APP_ID', 'coolify'),
'options' => [
- 'host' => env('PUSHER_BACKEND_HOST', 'coolify-realtime'),
- 'port' => env('PUSHER_BACKEND_PORT', 6001),
- 'scheme' => env('PUSHER_SCHEME', 'http'),
+ 'host' => env('PUSHER_HOST'),
+ 'port' => env('PUSHER_PORT', 443),
+ 'scheme' => env('PUSHER_SCHEME', 'https'),
'encrypted' => true,
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
],
diff --git a/config/constants.php b/config/constants.php
index f48b686826..9ca003f3b0 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -4,14 +4,12 @@ return [
'coolify' => [
'version' => env('COOLIFY_VERSION') ?: '4.4',
'helper_version' => '1.0.17',
- 'realtime_version' => '1.0.20',
'railpack_version' => '0.23.0',
'self_hosted' => env('SELF_HOSTED', true),
'autoupdate' => env('AUTOUPDATE'),
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
- 'registry_url' => env('REGISTRY_URL', 'docker.io'),
- 'helper_image' => env('HELPER_IMAGE', env('REGISTRY_URL', 'docker.io').'/coollabsio/coolify-helper'),
- 'realtime_image' => env('REALTIME_IMAGE', env('REGISTRY_URL', 'docker.io').'/coollabsio/coolify-realtime'),
+ 'registry_url' => env('REGISTRY_URL', 'ghcr.io'),
+ 'helper_image' => env('HELPER_IMAGE', env('REGISTRY_URL', 'ghcr.io').'/coollabsio/coolify-helper'),
'is_windows_docker_desktop' => env('IS_WINDOWS_DOCKER_DESKTOP', false),
'cdn_url' => env('CDN_URL', 'https://cdn.coollabs.io'),
'versions_url' => env('VERSIONS_URL', env('CDN_URL', 'https://cdn.coollabs.io').'/coolify/versions.json'),
diff --git a/config/reverb.php b/config/reverb.php
new file mode 100644
index 0000000000..5551e9be3a
--- /dev/null
+++ b/config/reverb.php
@@ -0,0 +1,102 @@
+ 'reverb',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Reverb Servers
+ |--------------------------------------------------------------------------
+ |
+ | Here you may define details for each of the supported Reverb servers.
+ | Each server has its own configuration options that are defined in
+ | the array below. You should ensure all the options are present.
+ |
+ */
+
+ 'servers' => [
+
+ 'reverb' => [
+ 'host' => '0.0.0.0',
+ 'port' => env('PUSHER_BACKEND_PORT', 6001),
+ 'path' => '',
+ 'hostname' => env('PUSHER_HOST'),
+ 'options' => [
+ 'tls' => [],
+ ],
+ 'max_request_size' => 10_000,
+ 'scaling' => [
+ 'enabled' => false,
+ 'channel' => 'reverb',
+ 'server' => [
+ 'url' => env('REDIS_URL'),
+ 'host' => env('REDIS_HOST', '127.0.0.1'),
+ 'port' => env('REDIS_PORT', '6379'),
+ 'username' => env('REDIS_USERNAME'),
+ 'password' => env('REDIS_PASSWORD'),
+ 'database' => env('REDIS_DB', '0'),
+ 'timeout' => env('REDIS_TIMEOUT', 60),
+ ],
+ ],
+ 'pulse_ingest_interval' => 15,
+ 'telescope_ingest_interval' => 15,
+ ],
+
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Reverb Applications
+ |--------------------------------------------------------------------------
+ |
+ | Here you may define how Reverb applications are managed. If you choose
+ | to use the "config" provider, you may define an array of apps which
+ | your server will support, including their connection credentials.
+ |
+ */
+
+ 'apps' => [
+
+ 'provider' => 'config',
+
+ 'apps' => [
+ [
+ 'key' => env('PUSHER_APP_KEY', 'coolify'),
+ 'secret' => env('PUSHER_APP_SECRET', 'coolify'),
+ 'app_id' => env('PUSHER_APP_ID', 'coolify'),
+ 'options' => [
+ 'host' => env('PUSHER_HOST', 'coolify'),
+ 'port' => env('PUSHER_PORT', 6001),
+ 'scheme' => env('PUSHER_SCHEME', 'http'),
+ 'useTLS' => env('PUSHER_SCHEME', 'http') === 'https',
+ ],
+ 'allowed_origins' => ['*'],
+ 'ping_interval' => 60,
+ 'activity_timeout' => 30,
+ 'max_connections' => null,
+ 'max_message_size' => 10_000,
+ 'accept_client_events_from' => 'members',
+ 'rate_limiting' => [
+ 'enabled' => false,
+ 'max_attempts' => 60,
+ 'decay_seconds' => 60,
+ 'terminate_on_limit' => false,
+ ],
+ ],
+ ],
+
+ ],
+
+];
diff --git a/docker-compose-maxio.dev.yml b/docker-compose-maxio.dev.yml
index 885d17f3c8..3d4525510e 100644
--- a/docker-compose-maxio.dev.yml
+++ b/docker-compose-maxio.dev.yml
@@ -10,12 +10,15 @@ services:
- GROUP_ID=${GROUPID:-1000}
ports:
- "${APP_PORT:-8000}:8080"
+ - "${FORWARD_PUSHER_PORT:-6001}:6001"
+ - "6002:6002"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
AUTORUN_ENABLED: false
- PUSHER_HOST: "${PUSHER_HOST:-}"
- PUSHER_PORT: "${PUSHER_PORT:-}"
+ PUSHER_HOST: "${PUSHER_HOST:-coolify}"
+ PUSHER_PORT: "${PUSHER_PORT:-6001}"
+ PUSHER_BACKEND_PORT: "${PUSHER_BACKEND_PORT:-6001}"
PUSHER_SCHEME: "${PUSHER_SCHEME:-http}"
PUSHER_APP_ID: "${PUSHER_APP_ID:-coolify}"
PUSHER_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
@@ -28,6 +31,8 @@ services:
volumes:
- .:/var/www/html/:cached
- dev_backups_data:/var/www/html/storage/app/backups
+ - ./docker/coolify-terminal/terminal-server.js:/terminal/terminal-server.js
+ - ./docker/coolify-terminal/terminal-utils.js:/terminal/terminal-utils.js
networks:
- coolify
postgres:
@@ -61,35 +66,6 @@ services:
timeout: 2s
volumes:
- dev_redis_data:/data
- soketi:
- image: coolify-realtime:dev
- pull_policy: never
- build:
- context: .
- dockerfile: ./docker/coolify-realtime/Dockerfile
- env_file:
- - .env
- ports:
- - "${FORWARD_SOKETI_PORT:-6001}:6001"
- - "6002:6002"
- extra_hosts:
- - "host.docker.internal:host-gateway"
- volumes:
- - ./storage:/var/www/html/storage
- - ./docker/coolify-realtime/terminal-server.js:/terminal/terminal-server.js
- - ./docker/coolify-realtime/terminal-utils.js:/terminal/terminal-utils.js
- environment:
- SOKETI_DEBUG: "false"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
- SOKETI_HOST: "${SOKETI_HOST:-0.0.0.0}"
- healthcheck:
- test: [ "CMD-SHELL", "curl -fsS http://127.0.0.1:6001/ready && curl -fsS http://127.0.0.1:6002/ready || exit 1" ]
- interval: 5s
- retries: 10
- timeout: 2s
- entrypoint: ["/bin/sh", "/soketi-entrypoint.sh"]
vite:
image: node:24-alpine
pull_policy: always
diff --git a/docker-compose.dev-multi.yml b/docker-compose.dev-multi.yml
index c8f2833117..26ba2236b6 100644
--- a/docker-compose.dev-multi.yml
+++ b/docker-compose.dev-multi.yml
@@ -10,7 +10,7 @@
# Optional profiles: vite, mailpit, minio, testing-host
# ./scripts/dev-instances up a --with vite mailpit
#
-# Ports (a / b): app 8000/8001, db 5432/5433, redis 6379/6380, soketi 6001/6011
+# Ports (a / b): app 8000/8001, db 5432/5433, redis 6379/6380, Reverb 6001/6011
services:
coolify:
@@ -24,6 +24,8 @@ services:
- GROUP_ID=${GROUPID:-1000}
ports:
- "${APP_PORT:-8000}:8080"
+ - "${FORWARD_PUSHER_PORT:-6001}:6001"
+ - "${FORWARD_TERMINAL_PORT:-6002}:6002"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
@@ -43,13 +45,14 @@ services:
REDIS_PORT: 6379
REDIS_PASSWORD: "${REDIS_PASSWORD:-null}"
COOLIFY_CONTAINER_ROLE: all
- PUSHER_HOST: ""
- PUSHER_PORT: ""
+ PUSHER_HOST: coolify
+ PUSHER_PORT: 6001
+ PUSHER_BACKEND_PORT: 6001
PUSHER_SCHEME: http
PUSHER_APP_ID: "${PUSHER_APP_ID:-coolify}"
PUSHER_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
PUSHER_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
- BROADCAST_CONNECTION: pusher
+ BROADCAST_CONNECTION: reverb
QUEUE_CONNECTION: redis
CACHE_STORE: redis
SESSION_DRIVER: redis
@@ -61,6 +64,8 @@ services:
volumes:
- .:/var/www/html/:cached
- backups_data:/var/www/html/storage/app/backups
+ - ./docker/coolify-terminal/terminal-server.js:/terminal/terminal-server.js
+ - ./docker/coolify-terminal/terminal-utils.js:/terminal/terminal-utils.js
depends_on:
postgres:
condition: service_healthy
@@ -104,36 +109,6 @@ services:
networks:
- coolify
- soketi:
- image: coolify-realtime:dev
- pull_policy: never
- build:
- context: .
- dockerfile: ./docker/coolify-realtime/Dockerfile
- ports:
- - "${FORWARD_SOKETI_PORT:-6001}:6001"
- - "${FORWARD_SOKETI_PORT_ALT:-6002}:6002"
- extra_hosts:
- - "host.docker.internal:host-gateway"
- volumes:
- - ./storage:/var/www/html/storage
- - ./docker/coolify-realtime/terminal-server.js:/terminal/terminal-server.js
- - ./docker/coolify-realtime/terminal-utils.js:/terminal/terminal-utils.js
- environment:
- SOKETI_DEBUG: "false"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
- SOKETI_HOST: "0.0.0.0"
- healthcheck:
- test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:6001/ready && curl -fsS http://127.0.0.1:6002/ready || exit 1"]
- interval: 5s
- retries: 10
- timeout: 2s
- entrypoint: ["/bin/sh", "/soketi-entrypoint.sh"]
- networks:
- - coolify
-
vite:
profiles: ["vite"]
image: node:24-alpine
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
index d33d9aab5c..6210d70bd4 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -10,13 +10,16 @@ services:
- GROUP_ID=${GROUPID:-1000}
ports:
- "${DEV_BIND_ADDRESS:-0.0.0.0}:${APP_PORT:-8000}:8080"
+ - "${DEV_BIND_ADDRESS:-0.0.0.0}:${FORWARD_PUSHER_PORT:-6001}:6001"
+ - "${DEV_BIND_ADDRESS:-0.0.0.0}:6002:6002"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
AUTORUN_ENABLED: false
COOLIFY_CONTAINER_ROLE: "${COOLIFY_CONTAINER_ROLE:-all}"
- PUSHER_HOST: "${PUSHER_HOST:-}"
- PUSHER_PORT: "${PUSHER_PORT:-}"
+ PUSHER_HOST: "${PUSHER_HOST:-coolify}"
+ PUSHER_PORT: "${PUSHER_PORT:-6001}"
+ PUSHER_BACKEND_PORT: "${PUSHER_BACKEND_PORT:-6001}"
PUSHER_SCHEME: "${PUSHER_SCHEME:-http}"
PUSHER_APP_ID: "${PUSHER_APP_ID:-coolify}"
PUSHER_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
@@ -29,6 +32,8 @@ services:
volumes:
- .:/var/www/html/:cached
- dev_backups_data:/var/www/html/storage/app/backups
+ - ./docker/coolify-terminal/terminal-server.js:/terminal/terminal-server.js
+ - ./docker/coolify-terminal/terminal-utils.js:/terminal/terminal-utils.js
networks:
- coolify
postgres:
@@ -62,35 +67,6 @@ services:
timeout: 2s
volumes:
- dev_redis_data:/data
- soketi:
- image: coolify-realtime:dev
- pull_policy: never
- build:
- context: .
- dockerfile: ./docker/coolify-realtime/Dockerfile
- env_file:
- - .env
- ports:
- - "${DEV_BIND_ADDRESS:-0.0.0.0}:${FORWARD_SOKETI_PORT:-6001}:6001"
- - "${DEV_BIND_ADDRESS:-0.0.0.0}:6002:6002"
- extra_hosts:
- - "host.docker.internal:host-gateway"
- volumes:
- - ./storage:/var/www/html/storage
- - ./docker/coolify-realtime/terminal-server.js:/terminal/terminal-server.js
- - ./docker/coolify-realtime/terminal-utils.js:/terminal/terminal-utils.js
- environment:
- SOKETI_DEBUG: "false"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
- SOKETI_HOST: "${SOKETI_HOST:-0.0.0.0}"
- healthcheck:
- test: [ "CMD-SHELL", "curl -fsS http://127.0.0.1:6001/ready && curl -fsS http://127.0.0.1:6002/ready || exit 1" ]
- interval: 5s
- retries: 10
- timeout: 2s
- entrypoint: ["/bin/sh", "/soketi-entrypoint.sh"]
vite:
image: node:24-alpine
pull_policy: always
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 2615ba63f9..169a65393a 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -19,12 +19,18 @@ services:
- PHP_FPM_PM_START_SERVERS=${PHP_FPM_PM_START_SERVERS:-1}
- PHP_FPM_PM_MIN_SPARE_SERVERS=${PHP_FPM_PM_MIN_SPARE_SERVERS:-1}
- PHP_FPM_PM_MAX_SPARE_SERVERS=${PHP_FPM_PM_MAX_SPARE_SERVERS:-10}
+ - PUSHER_PORT=${PUSHER_PORT:-6001}
+ - PUSHER_BACKEND_PORT=${PUSHER_BACKEND_PORT:-6001}
env_file:
- /data/coolify/source/.env
ports:
- "${APP_PORT:-8000}:8080"
+ - "${SOKETI_PORT:-6001}:6001"
+ - "${TERMINAL_PORT:-6002}:6002"
expose:
- "${APP_PORT:-8000}"
+ - "6001"
+ - "${TERMINAL_PORT:-6002}"
healthcheck:
test: curl --fail http://127.0.0.1:8080/api/health || exit 1
interval: 5s
@@ -36,8 +42,6 @@ services:
condition: service_healthy
redis:
condition: service_healthy
- soketi:
- condition: service_healthy
postgres:
volumes:
- coolify-db:/var/lib/postgresql/data
@@ -61,26 +65,6 @@ services:
interval: 5s
retries: 10
timeout: 2s
- soketi:
- image: '${REGISTRY_URL:-docker.io}/coollabsio/coolify-realtime:1.0.20'
- ports:
- - "${SOKETI_PORT:-6001}:6001"
- - "6002:6002"
- volumes:
- - /data/coolify/ssh:/var/www/html/storage/app/ssh
- environment:
- APP_NAME: "${APP_NAME:-Coolify}"
- SOKETI_DEBUG: "${SOKETI_DEBUG:-false}"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
- SOKETI_HOST: "${SOKETI_HOST:-0.0.0.0}"
- healthcheck:
- test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready || exit 1" ]
- interval: 5s
- retries: 10
- timeout: 2s
-
volumes:
coolify-db:
name: coolify-db
diff --git a/docker-compose.windows.yml b/docker-compose.windows.yml
index 106b3e1dc3..499584c14d 100644
--- a/docker-compose.windows.yml
+++ b/docker-compose.windows.yml
@@ -43,14 +43,20 @@ services:
- PUSHER_APP_ID
- PUSHER_APP_KEY
- PUSHER_APP_SECRET
+ - PUSHER_PORT
+ - PUSHER_BACKEND_PORT
- AUTOUPDATE=true
- SELF_HOSTED=true
- SSH_MUX_ENABLED=false
- IS_WINDOWS_DOCKER_DESKTOP=true
ports:
- "${APP_PORT:-8000}:8080"
+ - "${SOKETI_PORT:-6001}:6001"
+ - "${TERMINAL_PORT:-6002}:6002"
expose:
- "${APP_PORT:-8000}"
+ - "6001"
+ - "${TERMINAL_PORT:-6002}"
healthcheck:
test: curl --fail http://localhost:8080/api/health || exit 1
interval: 5s
@@ -96,30 +102,6 @@ services:
interval: 5s
retries: 10
timeout: 2s
- soketi:
- image: 'ghcr.io/coollabsio/coolify-realtime:1.0.20'
- pull_policy: always
- container_name: coolify-realtime
- restart: always
- env_file:
- - .env
- ports:
- - "${SOKETI_PORT:-6001}:6001"
- - "6002:6002"
- volumes:
- - ./ssh:/var/www/html/storage/app/ssh
- environment:
- APP_NAME: "${APP_NAME:-Coolify}"
- SOKETI_DEBUG: "${SOKETI_DEBUG:-false}"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
- SOKETI_HOST: "${SOKETI_HOST:-0.0.0.0}"
- healthcheck:
- test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready || exit 1" ]
- interval: 5s
- retries: 10
- timeout: 2s
volumes:
coolify-db:
diff --git a/docker-compose.yml b/docker-compose.yml
index 0fd3dda070..c4fc1233a6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -5,12 +5,14 @@ services:
working_dir: /var/www/html
extra_hosts:
- host.docker.internal:host-gateway
+ expose:
+ - "6001"
+ - "6002"
networks:
- coolify
depends_on:
- postgres
- redis
- - soketi
postgres:
image: postgres:15-alpine
container_name: coolify-db
@@ -23,13 +25,6 @@ services:
restart: always
networks:
- coolify
- soketi:
- container_name: coolify-realtime
- extra_hosts:
- - host.docker.internal:host-gateway
- restart: always
- networks:
- - coolify
networks:
coolify:
name: coolify
diff --git a/docker/coolify-realtime/Dockerfile b/docker/coolify-realtime/Dockerfile
deleted file mode 100644
index 8395d6f874..0000000000
--- a/docker/coolify-realtime/Dockerfile
+++ /dev/null
@@ -1,30 +0,0 @@
-# Versions
-# https://github.com/soketi/soketi/releases
-ARG SOKETI_VERSION=1.6-16-alpine
-# https://github.com/cloudflare/cloudflared/releases
-ARG CLOUDFLARED_VERSION=2025.7.0
-
-FROM quay.io/soketi/soketi:${SOKETI_VERSION}
-
-ARG TARGETPLATFORM
-ARG CLOUDFLARED_VERSION
-
-WORKDIR /terminal
-RUN apk upgrade --no-cache && \
- apk add --no-cache openssh-client make g++ python3 curl
-COPY docker/coolify-realtime/package*.json ./
-RUN npm ci
-RUN npm rebuild node-pty --update-binary
-COPY docker/coolify-realtime/soketi-entrypoint.sh /soketi-entrypoint.sh
-COPY docker/coolify-realtime/terminal-server.js /terminal/terminal-server.js
-COPY docker/coolify-realtime/terminal-utils.js /terminal/terminal-utils.js
-
-# Install Cloudflared based on architecture
-RUN if [ "${TARGETPLATFORM}" = "linux/amd64" ]; then \
- curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64" -o /usr/local/bin/cloudflared; \
- elif [ "${TARGETPLATFORM}" = "linux/arm64" ]; then \
- curl -sSL "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64" -o /usr/local/bin/cloudflared; \
- fi && \
- chmod +x /usr/local/bin/cloudflared
-
-ENTRYPOINT ["/bin/sh", "/soketi-entrypoint.sh"]
diff --git a/docker/coolify-realtime/soketi-entrypoint.sh b/docker/coolify-realtime/soketi-entrypoint.sh
deleted file mode 100644
index 7197e4a0c6..0000000000
--- a/docker/coolify-realtime/soketi-entrypoint.sh
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/bin/sh
-
-if [ "$1" = "watch" ]; then
- WATCH_MODE="--watch"
-else
- WATCH_MODE=""
-fi
-
-log() {
- echo "$(date '+%Y-%m-%d %H:%M:%S') [ENTRYPOINT] $*"
-}
-
-start_logger() {
- prefix="$1"
- fifo_path="$2"
-
- while read -r line; do
- echo "$(date '+%Y-%m-%d %H:%M:%S') [$prefix] $line"
- done < "$fifo_path" &
-}
-
-cleanup() {
- rm -f "$TERMINAL_LOG_FIFO" "$SOKETI_LOG_FIFO"
-}
-
-TERMINAL_LOG_FIFO="/tmp/coolify-terminal-log.$$"
-SOKETI_LOG_FIFO="/tmp/coolify-soketi-log.$$"
-
-rm -f "$TERMINAL_LOG_FIFO" "$SOKETI_LOG_FIFO"
-mkfifo "$TERMINAL_LOG_FIFO" "$SOKETI_LOG_FIFO"
-
-trap cleanup EXIT
-
-log "Starting realtime container"
-log "WATCH_MODE=${WATCH_MODE:-off}"
-log "SOKETI_DEBUG=${SOKETI_DEBUG:-unset}"
-log "NODE_OPTIONS=${NODE_OPTIONS:-unset}"
-
-start_logger "TERMINAL" "$TERMINAL_LOG_FIFO"
-TERMINAL_LOGGER_PID=$!
-
-start_logger "SOKETI" "$SOKETI_LOG_FIFO"
-SOKETI_LOGGER_PID=$!
-
-node $WATCH_MODE /terminal/terminal-server.js > "$TERMINAL_LOG_FIFO" 2>&1 &
-TERMINAL_PID=$!
-
-log "Terminal server started pid=$TERMINAL_PID logger_pid=$TERMINAL_LOGGER_PID"
-
-node /app/bin/server.js start > "$SOKETI_LOG_FIFO" 2>&1 &
-SOKETI_PID=$!
-
-log "Soketi started pid=$SOKETI_PID logger_pid=$SOKETI_LOGGER_PID"
-
-forward_signal() {
- log "Forwarding signal $1 to terminal=$TERMINAL_PID soketi=$SOKETI_PID"
-
- kill -"$1" "$TERMINAL_PID" 2>/dev/null || true
- kill -"$1" "$SOKETI_PID" 2>/dev/null || true
-}
-
-trap 'forward_signal TERM' TERM
-trap 'forward_signal INT' INT
-
-while true; do
- if ! kill -0 "$TERMINAL_PID" 2>/dev/null; then
- wait "$TERMINAL_PID"
- EXIT_CODE=$?
-
- log "Terminal server exited code=$EXIT_CODE; stopping soketi pid=$SOKETI_PID"
-
- kill "$SOKETI_PID" 2>/dev/null || true
- wait "$SOKETI_PID" 2>/dev/null || true
-
- exit "$EXIT_CODE"
- fi
-
- if ! kill -0 "$SOKETI_PID" 2>/dev/null; then
- wait "$SOKETI_PID"
- EXIT_CODE=$?
-
- log "Soketi exited code=$EXIT_CODE; stopping terminal pid=$TERMINAL_PID"
-
- kill "$TERMINAL_PID" 2>/dev/null || true
- wait "$TERMINAL_PID" 2>/dev/null || true
-
- exit "$EXIT_CODE"
- fi
-
- sleep 1
-done
diff --git a/docker/coolify-realtime/package-lock.json b/docker/coolify-terminal/package-lock.json
similarity index 99%
rename from docker/coolify-realtime/package-lock.json
rename to docker/coolify-terminal/package-lock.json
index da8e57be54..e59be50baf 100644
--- a/docker/coolify-realtime/package-lock.json
+++ b/docker/coolify-terminal/package-lock.json
@@ -1,5 +1,5 @@
{
- "name": "coolify-realtime",
+ "name": "coolify-terminal",
"lockfileVersion": 3,
"requires": true,
"packages": {
diff --git a/docker/coolify-realtime/package.json b/docker/coolify-terminal/package.json
similarity index 100%
rename from docker/coolify-realtime/package.json
rename to docker/coolify-terminal/package.json
diff --git a/docker/coolify-realtime/terminal-server.js b/docker/coolify-terminal/terminal-server.js
similarity index 99%
rename from docker/coolify-realtime/terminal-server.js
rename to docker/coolify-terminal/terminal-server.js
index 09f5bd5e12..00a9dd9590 100755
--- a/docker/coolify-realtime/terminal-server.js
+++ b/docker/coolify-terminal/terminal-server.js
@@ -18,7 +18,7 @@ import {
async function postToCoolify(path, headers) {
return new Promise((resolve, reject) => {
const request = http.request({
- hostname: 'coolify',
+ hostname: process.env.TERMINAL_AUTH_HOST || '127.0.0.1',
port: 8080,
path,
method: 'POST',
diff --git a/docker/coolify-realtime/terminal-utils.js b/docker/coolify-terminal/terminal-utils.js
similarity index 100%
rename from docker/coolify-realtime/terminal-utils.js
rename to docker/coolify-terminal/terminal-utils.js
diff --git a/docker/coolify-realtime/terminal-utils.test.js b/docker/coolify-terminal/terminal-utils.test.js
similarity index 100%
rename from docker/coolify-realtime/terminal-utils.test.js
rename to docker/coolify-terminal/terminal-utils.test.js
diff --git a/docker/development/Dockerfile b/docker/development/Dockerfile
index 62bb0ee241..6297da2cfe 100644
--- a/docker/development/Dockerfile
+++ b/docker/development/Dockerfile
@@ -56,6 +56,11 @@ RUN apk upgrade --no-cache && \
# Install system dependencies
RUN apk add --no-cache \
postgresql${POSTGRES_VERSION}-client \
+ nodejs \
+ npm \
+ make \
+ g++ \
+ python3 \
openssh-client \
openssl \
git \
@@ -85,6 +90,14 @@ RUN mkdir -p /usr/local/bin && \
COPY docker/development/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini
ENV PHP_OPCACHE_ENABLE=0
+# Install terminal WebSocket server dependencies
+COPY docker/coolify-terminal/package*.json /terminal/
+RUN npm ci --prefix /terminal && \
+ npm rebuild node-pty --prefix /terminal --update-binary
+COPY docker/coolify-terminal/terminal-server.js /terminal/terminal-server.js
+COPY docker/coolify-terminal/terminal-utils.js /terminal/terminal-utils.js
+RUN chown -R www-data:www-data /terminal
+
# Configure Nginx and S6 overlay
COPY docker/development/etc/nginx/conf.d/custom.conf /etc/nginx/conf.d/custom.conf
COPY docker/development/etc/nginx/site-opts.d/http.conf /etc/nginx/site-opts.d/http.conf
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/reverb/dependencies.d/init-setup b/docker/development/etc/s6-overlay/s6-rc.d/reverb/dependencies.d/init-setup
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/reverb/run b/docker/development/etc/s6-overlay/s6-rc.d/reverb/run
new file mode 100755
index 0000000000..e35e88a6cb
--- /dev/null
+++ b/docker/development/etc/s6-overlay/s6-rc.d/reverb/run
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+cd /var/www/html
+
+echo " INFO Reverb is starting..."
+exec php artisan reverb:start --host=0.0.0.0 --port=${PUSHER_BACKEND_PORT:-6001}
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/reverb/type b/docker/development/etc/s6-overlay/s6-rc.d/reverb/type
new file mode 100644
index 0000000000..5883cff0cd
--- /dev/null
+++ b/docker/development/etc/s6-overlay/s6-rc.d/reverb/type
@@ -0,0 +1 @@
+longrun
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/terminal-server/dependencies.d/init-setup b/docker/development/etc/s6-overlay/s6-rc.d/terminal-server/dependencies.d/init-setup
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/terminal-server/run b/docker/development/etc/s6-overlay/s6-rc.d/terminal-server/run
new file mode 100755
index 0000000000..b099b5dbcc
--- /dev/null
+++ b/docker/development/etc/s6-overlay/s6-rc.d/terminal-server/run
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+cd /var/www/html
+
+echo " INFO Terminal WebSocket server is starting..."
+exec node /terminal/terminal-server.js
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/terminal-server/type b/docker/development/etc/s6-overlay/s6-rc.d/terminal-server/type
new file mode 100644
index 0000000000..5883cff0cd
--- /dev/null
+++ b/docker/development/etc/s6-overlay/s6-rc.d/terminal-server/type
@@ -0,0 +1 @@
+longrun
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/reverb b/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/reverb
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/terminal-server b/docker/development/etc/s6-overlay/s6-rc.d/user/contents.d/terminal-server
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile
index 540602eceb..03d1145df7 100644
--- a/docker/production/Dockerfile
+++ b/docker/production/Dockerfile
@@ -108,6 +108,11 @@ RUN --mount=type=cache,target=/var/cache/apk \
apk upgrade && \
apk add --no-cache \
postgresql${POSTGRES_VERSION}-client \
+ nodejs \
+ npm \
+ make \
+ g++ \
+ python3 \
openssh-client \
git \
git-lfs \
@@ -158,6 +163,14 @@ COPY --chown=www-data:www-data changelogs/ ./changelogs/
RUN composer dump-autoload
+# Install terminal WebSocket server dependencies
+COPY docker/coolify-terminal/package*.json /terminal/
+RUN npm ci --prefix /terminal && \
+ npm rebuild node-pty --prefix /terminal --update-binary
+COPY docker/coolify-terminal/terminal-server.js /terminal/terminal-server.js
+COPY docker/coolify-terminal/terminal-utils.js /terminal/terminal-utils.js
+RUN chown -R www-data:www-data /terminal
+
# Configure Nginx and S6 overlay
COPY docker/production/etc/nginx/conf.d/custom.conf /etc/nginx/conf.d/custom.conf
COPY docker/production/etc/nginx/site-opts.d/http.conf /etc/nginx/site-opts.d/http.conf
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/reverb/dependencies.d/init-script b/docker/production/etc/s6-overlay/s6-rc.d/reverb/dependencies.d/init-script
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/reverb/run b/docker/production/etc/s6-overlay/s6-rc.d/reverb/run
new file mode 100755
index 0000000000..e35e88a6cb
--- /dev/null
+++ b/docker/production/etc/s6-overlay/s6-rc.d/reverb/run
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+cd /var/www/html
+
+echo " INFO Reverb is starting..."
+exec php artisan reverb:start --host=0.0.0.0 --port=${PUSHER_BACKEND_PORT:-6001}
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/reverb/type b/docker/production/etc/s6-overlay/s6-rc.d/reverb/type
new file mode 100644
index 0000000000..5883cff0cd
--- /dev/null
+++ b/docker/production/etc/s6-overlay/s6-rc.d/reverb/type
@@ -0,0 +1 @@
+longrun
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/terminal-server/dependencies.d/init-script b/docker/production/etc/s6-overlay/s6-rc.d/terminal-server/dependencies.d/init-script
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/terminal-server/run b/docker/production/etc/s6-overlay/s6-rc.d/terminal-server/run
new file mode 100755
index 0000000000..b099b5dbcc
--- /dev/null
+++ b/docker/production/etc/s6-overlay/s6-rc.d/terminal-server/run
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+cd /var/www/html
+
+echo " INFO Terminal WebSocket server is starting..."
+exec node /terminal/terminal-server.js
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/terminal-server/type b/docker/production/etc/s6-overlay/s6-rc.d/terminal-server/type
new file mode 100644
index 0000000000..5883cff0cd
--- /dev/null
+++ b/docker/production/etc/s6-overlay/s6-rc.d/terminal-server/type
@@ -0,0 +1 @@
+longrun
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/reverb b/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/reverb
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/terminal-server b/docker/production/etc/s6-overlay/s6-rc.d/user/contents.d/terminal-server
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/jean.json b/jean.json
index 7e4bcc00bc..77cf921f7a 100644
--- a/jean.json
+++ b/jean.json
@@ -2,7 +2,7 @@
"scripts": {
"setup": "cp $JEAN_ROOT_PATH/.env .",
"teardown": null,
- "run": "docker rm -f coolify coolify-minio-init coolify-realtime coolify-minio coolify-testing-host coolify-redis coolify-db coolify-mail coolify-vite; docker compose -f docker-compose.yml -f docker-compose.dev.yml up; docker compose -f docker-compose.yml -f docker-compose.dev.yml down"
+ "run": "docker rm -f coolify coolify-minio-init coolify-minio coolify-testing-host coolify-redis coolify-db coolify-mail coolify-vite; docker compose -f docker-compose.yml -f docker-compose.dev.yml up; docker compose -f docker-compose.yml -f docker-compose.dev.yml down"
},
"ports": [
{
diff --git a/other/nightly/.env.production b/other/nightly/.env.production
index cda3214d2d..f872a214f9 100644
--- a/other/nightly/.env.production
+++ b/other/nightly/.env.production
@@ -10,6 +10,7 @@ REDIS_PASSWORD=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
+PUSHER_BACKEND_PORT=6001
ROOT_USERNAME=
ROOT_USER_EMAIL=
diff --git a/other/nightly/docker-compose.prod.yml b/other/nightly/docker-compose.prod.yml
index ebf12379d5..169a65393a 100644
--- a/other/nightly/docker-compose.prod.yml
+++ b/other/nightly/docker-compose.prod.yml
@@ -19,12 +19,18 @@ services:
- PHP_FPM_PM_START_SERVERS=${PHP_FPM_PM_START_SERVERS:-1}
- PHP_FPM_PM_MIN_SPARE_SERVERS=${PHP_FPM_PM_MIN_SPARE_SERVERS:-1}
- PHP_FPM_PM_MAX_SPARE_SERVERS=${PHP_FPM_PM_MAX_SPARE_SERVERS:-10}
+ - PUSHER_PORT=${PUSHER_PORT:-6001}
+ - PUSHER_BACKEND_PORT=${PUSHER_BACKEND_PORT:-6001}
env_file:
- /data/coolify/source/.env
ports:
- "${APP_PORT:-8000}:8080"
+ - "${SOKETI_PORT:-6001}:6001"
+ - "${TERMINAL_PORT:-6002}:6002"
expose:
- "${APP_PORT:-8000}"
+ - "6001"
+ - "${TERMINAL_PORT:-6002}"
healthcheck:
test: curl --fail http://127.0.0.1:8080/api/health || exit 1
interval: 5s
@@ -36,8 +42,6 @@ services:
condition: service_healthy
redis:
condition: service_healthy
- soketi:
- condition: service_healthy
postgres:
volumes:
- coolify-db:/var/lib/postgresql/data
@@ -61,26 +65,6 @@ services:
interval: 5s
retries: 10
timeout: 2s
- soketi:
- image: '${REGISTRY_URL:-docker.io}/coollabsio/coolify-realtime:1.0.18'
- ports:
- - "${SOKETI_PORT:-6001}:6001"
- - "6002:6002"
- volumes:
- - /data/coolify/ssh:/var/www/html/storage/app/ssh
- environment:
- APP_NAME: "${APP_NAME:-Coolify}"
- SOKETI_DEBUG: "${SOKETI_DEBUG:-false}"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
- SOKETI_HOST: "${SOKETI_HOST:-0.0.0.0}"
- healthcheck:
- test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready || exit 1" ]
- interval: 5s
- retries: 10
- timeout: 2s
-
volumes:
coolify-db:
name: coolify-db
diff --git a/other/nightly/docker-compose.windows.yml b/other/nightly/docker-compose.windows.yml
index 32524c4f43..302c89c27f 100644
--- a/other/nightly/docker-compose.windows.yml
+++ b/other/nightly/docker-compose.windows.yml
@@ -42,14 +42,20 @@ services:
- PUSHER_APP_ID
- PUSHER_APP_KEY
- PUSHER_APP_SECRET
+ - PUSHER_PORT
+ - PUSHER_BACKEND_PORT
- AUTOUPDATE=true
- SELF_HOSTED=true
- SSH_MUX_ENABLED=false
- IS_WINDOWS_DOCKER_DESKTOP=true
ports:
- "${APP_PORT:-8000}:8080"
+ - "${SOKETI_PORT:-6001}:6001"
+ - "${TERMINAL_PORT:-6002}:6002"
expose:
- "${APP_PORT:-8000}"
+ - "6001"
+ - "${TERMINAL_PORT:-6002}"
healthcheck:
test: curl --fail http://localhost:8080/api/health || exit 1
interval: 5s
@@ -95,30 +101,6 @@ services:
interval: 5s
retries: 10
timeout: 2s
- soketi:
- image: 'ghcr.io/coollabsio/coolify-realtime:1.0.18'
- pull_policy: always
- container_name: coolify-realtime
- restart: always
- env_file:
- - .env
- ports:
- - "${SOKETI_PORT:-6001}:6001"
- - "6002:6002"
- volumes:
- - ./ssh:/var/www/html/storage/app/ssh
- environment:
- APP_NAME: "${APP_NAME:-Coolify}"
- SOKETI_DEBUG: "${SOKETI_DEBUG:-false}"
- SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
- SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
- SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
- SOKETI_HOST: "${SOKETI_HOST:-0.0.0.0}"
- healthcheck:
- test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready || exit 1" ]
- interval: 5s
- retries: 10
- timeout: 2s
volumes:
coolify-db:
diff --git a/other/nightly/docker-compose.yml b/other/nightly/docker-compose.yml
index 0fd3dda070..c4fc1233a6 100644
--- a/other/nightly/docker-compose.yml
+++ b/other/nightly/docker-compose.yml
@@ -5,12 +5,14 @@ services:
working_dir: /var/www/html
extra_hosts:
- host.docker.internal:host-gateway
+ expose:
+ - "6001"
+ - "6002"
networks:
- coolify
depends_on:
- postgres
- redis
- - soketi
postgres:
image: postgres:15-alpine
container_name: coolify-db
@@ -23,13 +25,6 @@ services:
restart: always
networks:
- coolify
- soketi:
- container_name: coolify-realtime
- extra_hosts:
- - host.docker.internal:host-gateway
- restart: always
- networks:
- - coolify
networks:
coolify:
name: coolify
diff --git a/other/nightly/install.sh b/other/nightly/install.sh
index 595dac2a51..7d5f868dc8 100755
--- a/other/nightly/install.sh
+++ b/other/nightly/install.sh
@@ -320,16 +320,11 @@ fi
VERSIONS_JSON=$(curl -L --silent $CDN/versions.json)
LATEST_VERSION=$(echo "$VERSIONS_JSON" | grep -i version | xargs | awk '{print $2}' | tr -d ',')
LATEST_HELPER_VERSION=$(echo "$VERSIONS_JSON" | grep -i version | xargs | awk '{print $6}' | tr -d ',')
-LATEST_REALTIME_VERSION=$(echo "$VERSIONS_JSON" | grep -i version | xargs | awk '{print $8}' | tr -d ',')
if [ -z "$LATEST_HELPER_VERSION" ]; then
LATEST_HELPER_VERSION=latest
fi
-if [ -z "$LATEST_REALTIME_VERSION" ]; then
- LATEST_REALTIME_VERSION=latest
-fi
-
case "$OS_TYPE" in
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine | postmarketos | tencentos) ;;
*)
@@ -350,7 +345,6 @@ echo "| Operating System | $OS_TYPE $OS_VERSION"
echo "| Docker | $DOCKER_VERSION"
echo "| Coolify | $LATEST_VERSION"
echo "| Helper | $LATEST_HELPER_VERSION"
-echo "| Realtime | $LATEST_REALTIME_VERSION"
echo "| Docker Pool | $DOCKER_ADDRESS_POOL_BASE (size $DOCKER_ADDRESS_POOL_SIZE)"
echo "| Registry URL | $REGISTRY_URL"
echo "---------------------------------------------"
@@ -846,6 +840,7 @@ update_env_var "REDIS_PASSWORD" "$(openssl rand -base64 32)"
update_env_var "PUSHER_APP_ID" "$(openssl rand -hex 32)"
update_env_var "PUSHER_APP_KEY" "$(openssl rand -hex 32)"
update_env_var "PUSHER_APP_SECRET" "$(openssl rand -hex 32)"
+update_env_var "PUSHER_BACKEND_PORT" "6001"
# Add default root user credentials from environment variables
if [ -n "$ROOT_USERNAME" ] && [ -n "$ROOT_USER_EMAIL" ] && [ -n "$ROOT_USER_PASSWORD" ]; then
diff --git a/other/nightly/upgrade.sh b/other/nightly/upgrade.sh
index c5f38df6e0..0e441ad380 100644
--- a/other/nightly/upgrade.sh
+++ b/other/nightly/upgrade.sh
@@ -151,6 +151,7 @@ set_env_var "REGISTRY_URL" "$REGISTRY_URL"
update_env_var "PUSHER_APP_ID" "$(openssl rand -hex 32)"
update_env_var "PUSHER_APP_KEY" "$(openssl rand -hex 32)"
update_env_var "PUSHER_APP_SECRET" "$(openssl rand -hex 32)"
+update_env_var "PUSHER_BACKEND_PORT" "6001"
log "Environment variables check complete"
echo " Done."
@@ -248,7 +249,7 @@ nohup bash -c "
}
# Stop and remove containers
- for container in coolify coolify-db coolify-redis coolify-realtime; do
+ for container in coolify coolify-db coolify-redis; do
if docker ps -a --format '{{.Names}}' | grep -q \"^\${container}\$\"; then
log \"Stopping container: \${container}\"
docker stop \"\$container\" >>\"\$LOGFILE\" 2>&1 || true
diff --git a/other/nightly/versions.json b/other/nightly/versions.json
index 6eb14d45e8..7262de886a 100644
--- a/other/nightly/versions.json
+++ b/other/nightly/versions.json
@@ -9,9 +9,6 @@
"helper": {
"version": "1.0.17"
},
- "realtime": {
- "version": "1.0.20"
- },
"sentinel": {
"version": "1.0.1"
}
diff --git a/phpunit.xml b/phpunit.xml
index 6ddcaed7dc..b1091f2abd 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -22,7 +22,7 @@
-
+
diff --git a/resources/views/layouts/base.blade.php b/resources/views/layouts/base.blade.php
index 66201da936..61df6d22f1 100644
--- a/resources/views/layouts/base.blade.php
+++ b/resources/views/layouts/base.blade.php
@@ -284,8 +284,7 @@
window.Pusher = Pusher;
const EchoConstructor = typeof Echo === 'function' ? Echo : Echo.default;
window.Echo = new EchoConstructor({
- broadcaster: 'pusher',
- cluster: "{{ config('constants.pusher.host') }}" || window.location.hostname,
+ broadcaster: 'reverb',
key: "{{ config('constants.pusher.app_key') }}" || 'coolify',
wsHost: "{{ config('constants.pusher.host') }}" || window.location.hostname,
wsPort: "{{ getRealtime() }}",
diff --git a/scripts/dev-instances b/scripts/dev-instances
index eac6b84383..36437807e6 100755
--- a/scripts/dev-instances
+++ b/scripts/dev-instances
@@ -12,8 +12,8 @@
# ./scripts/dev-instances exec a php artisan migrate --force
#
# Ports (fixed):
-# a app 8000 db 5432 redis 6379 soketi 6001/6002 flux 6443
-# b app 8001 db 5433 redis 6380 soketi 6011/6012 flux 6444
+# a app 8000 db 5432 redis 6379 Reverb 6001/6002 flux 6443
+# b app 8001 db 5433 redis 6380 Reverb 6011/6012 flux 6444
#
# Frontend: multi-instance uses npm run build (shared public/build). Do not use
# two Vite HMR servers — public/hot is a single shared file.
@@ -94,8 +94,8 @@ APP_KEY=${existing_key}
APP_PORT=${app_port}
FORWARD_DB_PORT=$((5432 + offset))
FORWARD_REDIS_PORT=$((6379 + offset))
-FORWARD_SOKETI_PORT=$((6001 + offset * 10))
-FORWARD_SOKETI_PORT_ALT=$((6002 + offset * 10))
+FORWARD_PUSHER_PORT=$((6001 + offset * 10))
+FORWARD_TERMINAL_PORT=$((6002 + offset * 10))
FORWARD_FLUX_PORT=$((6443 + offset))
VITE_PORT=$((5173 + offset))
FORWARD_MAILPIT_PORT=$((1025 + offset * 100))
@@ -276,7 +276,7 @@ cmd_urls() {
"$(grep -E '^APP_URL=' "$envf" | cut -d= -f2-)" \
"$(grep -E '^FORWARD_DB_PORT=' "$envf" | cut -d= -f2-)" \
"$(grep -E '^FORWARD_REDIS_PORT=' "$envf" | cut -d= -f2-)" \
- "$(grep -E '^FORWARD_SOKETI_PORT=' "$envf" | cut -d= -f2-)"
+ "$(grep -E '^FORWARD_PUSHER_PORT=' "$envf" | cut -d= -f2-)"
done
}
diff --git a/scripts/install.sh b/scripts/install.sh
index 226b1cc5e0..e2060b34d9 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -321,16 +321,11 @@ fi
VERSIONS_JSON=$(curl -L --silent $CDN/versions.json)
LATEST_VERSION=$(echo "$VERSIONS_JSON" | grep -i version | xargs | awk '{print $2}' | tr -d ',')
LATEST_HELPER_VERSION=$(echo "$VERSIONS_JSON" | grep -i version | xargs | awk '{print $6}' | tr -d ',')
-LATEST_REALTIME_VERSION=$(echo "$VERSIONS_JSON" | grep -i version | xargs | awk '{print $8}' | tr -d ',')
if [ -z "$LATEST_HELPER_VERSION" ]; then
LATEST_HELPER_VERSION=latest
fi
-if [ -z "$LATEST_REALTIME_VERSION" ]; then
- LATEST_REALTIME_VERSION=latest
-fi
-
case "$OS_TYPE" in
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine | postmarketos | tencentos) ;;
*)
@@ -351,7 +346,6 @@ echo "| Operating System | $OS_TYPE $OS_VERSION"
echo "| Docker | $DOCKER_VERSION"
echo "| Coolify | $LATEST_VERSION"
echo "| Helper | $LATEST_HELPER_VERSION"
-echo "| Realtime | $LATEST_REALTIME_VERSION"
echo "| Docker Pool | $DOCKER_ADDRESS_POOL_BASE (size $DOCKER_ADDRESS_POOL_SIZE)"
echo "| Registry URL | $REGISTRY_URL"
echo "---------------------------------------------"
@@ -847,6 +841,7 @@ update_env_var "REDIS_PASSWORD" "$(openssl rand -base64 32)"
update_env_var "PUSHER_APP_ID" "$(openssl rand -hex 32)"
update_env_var "PUSHER_APP_KEY" "$(openssl rand -hex 32)"
update_env_var "PUSHER_APP_SECRET" "$(openssl rand -hex 32)"
+update_env_var "PUSHER_BACKEND_PORT" "6001"
# Add default root user credentials from environment variables
if [ -n "$ROOT_USERNAME" ] && [ -n "$ROOT_USER_EMAIL" ] && [ -n "$ROOT_USER_PASSWORD" ]; then
diff --git a/scripts/upgrade.sh b/scripts/upgrade.sh
index 5baac23acb..c3cdf00593 100644
--- a/scripts/upgrade.sh
+++ b/scripts/upgrade.sh
@@ -151,6 +151,7 @@ set_env_var "REGISTRY_URL" "$REGISTRY_URL"
update_env_var "PUSHER_APP_ID" "$(openssl rand -hex 32)"
update_env_var "PUSHER_APP_KEY" "$(openssl rand -hex 32)"
update_env_var "PUSHER_APP_SECRET" "$(openssl rand -hex 32)"
+update_env_var "PUSHER_BACKEND_PORT" "6001"
log "Environment variables check complete"
echo " Done."
@@ -261,7 +262,7 @@ nohup bash -c "
}
# Stop and remove containers
- for container in coolify coolify-db coolify-redis coolify-realtime; do
+ for container in coolify coolify-db coolify-redis; do
if docker ps -a --format '{{.Names}}' | grep -q \"^\${container}\$\"; then
log \"Stopping container: \${container}\"
docker stop \"\$container\" >>\"\$LOGFILE\" 2>&1 || true
diff --git a/tests/Feature/PullChangelogTest.php b/tests/Feature/PullChangelogTest.php
index 7793b0b775..faadfb2cee 100644
--- a/tests/Feature/PullChangelogTest.php
+++ b/tests/Feature/PullChangelogTest.php
@@ -32,9 +32,9 @@ afterEach(function () {
File::delete(base_path('changelogs/1999-01.json'));
});
-test('releases_url config defaults to the GitHub raw source', function () {
+test('releases_url config defaults to the Coollabs CDN', function () {
expect(config('constants.coolify.releases_url'))
- ->toBe('https://cdn.coollabs.io/coolify/service-templates-latest.json');
+ ->toBe('https://cdn.coollabs.io/coolify/releases.json');
});
test('PullChangelog fetches from the configured releases_url and writes the changelog', function () {
diff --git a/tests/Feature/RealtimeTerminalPackagingTest.php b/tests/Feature/RealtimeTerminalPackagingTest.php
index 4b400b49a6..d144ebd696 100644
--- a/tests/Feature/RealtimeTerminalPackagingTest.php
+++ b/tests/Feature/RealtimeTerminalPackagingTest.php
@@ -193,16 +193,19 @@ it('does not overlay the session expiry label on the application terminal', func
->not->toContain('terminal-session-expiry');
});
-it('copies the realtime terminal utilities into the container image', function () {
- $dockerfile = file_get_contents(base_path('docker/coolify-realtime/Dockerfile'));
+it('copies the terminal utilities into the Coolify container images', function (string $dockerfile) {
+ $dockerfile = file_get_contents(base_path($dockerfile));
- expect($dockerfile)->toContain('COPY docker/coolify-realtime/terminal-utils.js /terminal/terminal-utils.js');
-});
+ expect($dockerfile)->toContain('COPY docker/coolify-terminal/terminal-utils.js /terminal/terminal-utils.js');
+})->with([
+ 'production image' => 'docker/production/Dockerfile',
+ 'development image' => 'docker/development/Dockerfile',
+]);
it('mounts the realtime terminal utilities in local development compose files', function (string $composeFile) {
$composeContents = file_get_contents(base_path($composeFile));
- expect($composeContents)->toContain('./docker/coolify-realtime/terminal-utils.js:/terminal/terminal-utils.js');
+ expect($composeContents)->toContain('./docker/coolify-terminal/terminal-utils.js:/terminal/terminal-utils.js');
})->with([
'default dev compose' => 'docker-compose.dev.yml',
'maxio dev compose' => 'docker-compose-maxio.dev.yml',
@@ -219,7 +222,7 @@ it('keeps terminal browser logging restricted to development or explicit diagnos
});
it('keeps realtime terminal server logging behind the explicit debug flag', function () {
- $terminalServer = file_get_contents(base_path('docker/coolify-realtime/terminal-server.js'));
+ $terminalServer = file_get_contents(base_path('docker/coolify-terminal/terminal-server.js'));
expect($terminalServer)
->toContain('const debugOverride = String(process.env.TERMINAL_DEBUG')
@@ -229,7 +232,7 @@ it('keeps realtime terminal server logging behind the explicit debug flag', func
});
it('configures a server-initiated WebSocket heartbeat to survive proxy idle timeouts', function () {
- $terminalServer = file_get_contents(base_path('docker/coolify-realtime/terminal-server.js'));
+ $terminalServer = file_get_contents(base_path('docker/coolify-terminal/terminal-server.js'));
expect($terminalServer)
->toContain('ws.isAlive = true;')
@@ -254,7 +257,7 @@ it('uses a fast probe timeout when the tab regains visibility', function () {
});
it('does not hard close terminal sessions after 30 minutes on the server', function () {
- $terminalServer = file_get_contents(base_path('docker/coolify-realtime/terminal-server.js'));
+ $terminalServer = file_get_contents(base_path('docker/coolify-terminal/terminal-server.js'));
expect($terminalServer)
->not->toContain('IDLE_TIMEOUT_MS = 30 * 60 * 1000')
@@ -304,7 +307,7 @@ it('replays the last command on reconnect so the PTY respawns automatically', fu
});
it('buffers messages received before the realtime server finishes auth so the replay is not lost', function () {
- $terminalServer = file_get_contents(base_path('docker/coolify-realtime/terminal-server.js'));
+ $terminalServer = file_get_contents(base_path('docker/coolify-terminal/terminal-server.js'));
expect($terminalServer)
->toContain('authReady: false')
diff --git a/tests/Feature/ReverbAndTerminalPackagingTest.php b/tests/Feature/ReverbAndTerminalPackagingTest.php
new file mode 100644
index 0000000000..1461ec9707
--- /dev/null
+++ b/tests/Feature/ReverbAndTerminalPackagingTest.php
@@ -0,0 +1,173 @@
+toContain('"laravel/reverb"')
+ ->and(file_get_contents(config_path('broadcasting.php')))
+ ->toContain("'default' => env('BROADCAST_CONNECTION', env('BROADCAST_DRIVER', 'reverb'))")
+ ->toContain("'reverb' => [")
+ ->toContain("'key' => env('PUSHER_APP_KEY', 'coolify')")
+ ->toContain("'secret' => env('PUSHER_APP_SECRET', 'coolify')")
+ ->toContain("'app_id' => env('PUSHER_APP_ID', 'coolify')")
+ ->toContain("'host' => env('PUSHER_HOST', 'coolify')")
+ ->toContain("'port' => env('PUSHER_BACKEND_PORT', 6001)")
+ ->and(file_exists(config_path('reverb.php')))->toBeTrue();
+});
+
+it('runs Reverb and terminal websocket services inside the Coolify containers', function (string $dockerfile, string $dependencyService) {
+ $dockerfileContents = file_get_contents(base_path($dockerfile));
+
+ expect($dockerfileContents)
+ ->toContain('nodejs')
+ ->toContain('npm')
+ ->toContain('COPY docker/coolify-terminal/package*.json /terminal/')
+ ->toContain('COPY docker/coolify-terminal/terminal-server.js /terminal/terminal-server.js')
+ ->toContain('COPY docker/coolify-terminal/terminal-utils.js /terminal/terminal-utils.js')
+ ->toContain('npm ci --prefix /terminal')
+ ->and(file_get_contents(base_path(dirname($dockerfile).'/etc/s6-overlay/s6-rc.d/reverb/run')))
+ ->toContain('exec php artisan reverb:start --host=0.0.0.0 --port=${PUSHER_BACKEND_PORT:-6001}')
+ ->not->toContain('PUSHER_ENABLED')
+ ->not->toContain('Reverb is disabled')
+ ->and(file_get_contents(base_path(dirname($dockerfile).'/etc/s6-overlay/s6-rc.d/terminal-server/run')))
+ ->toContain('exec node /terminal/terminal-server.js')
+ ->and(file_exists(base_path(dirname($dockerfile)."/etc/s6-overlay/s6-rc.d/reverb/dependencies.d/{$dependencyService}")))->toBeTrue()
+ ->and(file_exists(base_path(dirname($dockerfile)."/etc/s6-overlay/s6-rc.d/terminal-server/dependencies.d/{$dependencyService}")))->toBeTrue()
+ ->and(file_exists(base_path(dirname($dockerfile).'/etc/s6-overlay/s6-rc.d/user/contents.d/reverb')))->toBeTrue()
+ ->and(file_exists(base_path(dirname($dockerfile).'/etc/s6-overlay/s6-rc.d/user/contents.d/terminal-server')))->toBeTrue();
+})->with([
+ 'production image' => ['docker/production/Dockerfile', 'init-script'],
+ 'development image' => ['docker/development/Dockerfile', 'init-setup'],
+]);
+
+it('removes the dedicated realtime service from bundled compose files', function (string $composeFile, bool $hasRuntimeEnvironment) {
+ $composeContents = file_get_contents(base_path($composeFile));
+
+ expect($composeContents)
+ ->not->toContain('coolify-realtime')
+ ->not->toContain('soketi:')
+ ->not->toContain('SOKETI_DEFAULT_APP_ID')
+ ->toContain('6001')
+ ->toContain('6002')
+ ->not->toContain('REVERB_');
+
+ if ($hasRuntimeEnvironment) {
+ expect($composeContents)->toContain('PUSHER_BACKEND_PORT');
+ }
+})->with([
+ 'base compose' => ['docker-compose.yml', false],
+ 'production compose' => ['docker-compose.prod.yml', true],
+ 'development compose' => ['docker-compose.dev.yml', true],
+ 'maxio development compose' => ['docker-compose-maxio.dev.yml', true],
+ 'multi-instance development compose' => ['docker-compose.dev-multi.yml', true],
+ 'windows compose' => ['docker-compose.windows.yml', true],
+]);
+
+it('keeps the internal Reverb listen port separate from the public Pusher port', function () {
+ expect(file_get_contents(config_path('reverb.php')))
+ ->toContain("'port' => env('PUSHER_BACKEND_PORT', 6001)")
+ ->toContain("'port' => env('PUSHER_PORT', 6001)")
+ ->and(file_get_contents(base_path('docker/production/etc/s6-overlay/s6-rc.d/reverb/run')))
+ ->toContain('exec php artisan reverb:start --host=0.0.0.0 --port=${PUSHER_BACKEND_PORT:-6001}')
+ ->and(file_get_contents(base_path('docker/development/etc/s6-overlay/s6-rc.d/reverb/run')))
+ ->toContain('exec php artisan reverb:start --host=0.0.0.0 --port=${PUSHER_BACKEND_PORT:-6001}');
+});
+
+it('proxies Reverb and terminal websocket traffic to the Coolify app container', function () {
+ $serverModel = file_get_contents(app_path('Models/Server.php'));
+
+ expect($serverModel)
+ ->toContain("'rule' => \"Host(`{\$host}`) && PathPrefix(`/app`)\"")
+ ->toContain("'rule' => \"Host(`{\$host}`) && PathPrefix(`/apps`)\"")
+ ->toContain("'rule' => \"Host(`{\$host}`) && PathPrefix(`/terminal/ws`)\"")
+ ->toContain("'url' => 'http://coolify:6001'")
+ ->toContain("'url' => 'http://coolify:6002'")
+ ->toContain('reverse_proxy coolify:6001')
+ ->toContain('reverse_proxy coolify:6002')
+ ->not->toContain('http://coolify-realtime:6001')
+ ->not->toContain('http://coolify-realtime:6002')
+ ->not->toContain('reverse_proxy coolify-realtime');
+});
+
+it('uses Pusher environment keys for self-hosted Reverb compatibility', function () {
+ $files = [
+ '.env.production',
+ '.env.windows-docker-desktop.example',
+ 'docker-compose.prod.yml',
+ 'docker-compose.dev.yml',
+ 'docker-compose-maxio.dev.yml',
+ 'docker-compose.windows.yml',
+ 'scripts/install.sh',
+ 'scripts/upgrade.sh',
+ 'other/nightly/.env.production',
+ 'other/nightly/docker-compose.prod.yml',
+ 'other/nightly/docker-compose.windows.yml',
+ 'other/nightly/install.sh',
+ 'other/nightly/upgrade.sh',
+ ];
+
+ foreach ($files as $file) {
+ expect(file_get_contents(base_path($file)))
+ ->toContain('PUSHER_')
+ ->not->toContain('REVERB_');
+ }
+});
+
+it('keeps the public websocket port adaptive and configures only the internal Reverb port', function () {
+ expect(file_get_contents(base_path('.env.production')))
+ ->not->toContain('PUSHER_PORT=')
+ ->not->toContain('PUSHER_BACKEND_PORT=')
+ ->and(file_get_contents(base_path('.env.windows-docker-desktop.example')))
+ ->not->toContain('PUSHER_PORT=')
+ ->toContain('PUSHER_BACKEND_PORT=6001')
+ ->and(file_get_contents(base_path('scripts/install.sh')))
+ ->not->toContain('update_env_var "PUSHER_PORT"')
+ ->toContain('update_env_var "PUSHER_BACKEND_PORT" "6001"')
+ ->and(file_get_contents(base_path('scripts/upgrade.sh')))
+ ->not->toContain('update_env_var "PUSHER_PORT"')
+ ->toContain('update_env_var "PUSHER_BACKEND_PORT" "6001"');
+});
+
+it('does not use the browser websocket port as the Docker host port', function (string $composeFile) {
+ expect(file_get_contents(base_path($composeFile)))
+ ->toContain('"${SOKETI_PORT:-6001}:6001"')
+ ->not->toContain('"${PUSHER_PORT:-6001}:6001"');
+})->with([
+ 'production compose' => ['docker-compose.prod.yml'],
+ 'nightly production compose' => ['other/nightly/docker-compose.prod.yml'],
+ 'windows compose' => ['docker-compose.windows.yml'],
+ 'nightly windows compose' => ['other/nightly/docker-compose.windows.yml'],
+]);
+
+it('preserves existing public websocket port overrides during install and upgrade', function (string $script) {
+ $contents = file_get_contents(base_path($script));
+
+ expect($contents)
+ ->not->toContain('normalize_pusher_port')
+ ->not->toMatch('/(?:set|update)_env_var "PUSHER_PORT"/');
+})->with([
+ 'install script' => ['scripts/install.sh'],
+ 'upgrade script' => ['scripts/upgrade.sh'],
+ 'nightly install script' => ['other/nightly/install.sh'],
+ 'nightly upgrade script' => ['other/nightly/upgrade.sh'],
+]);
+
+it('stops publishing or preserving the obsolete realtime image', function () {
+ $productionInstallScript = file_get_contents(base_path('scripts/install.sh'));
+ $nightlyInstallScript = file_get_contents(base_path('other/nightly/install.sh'));
+
+ expect(file_get_contents(config_path('constants.php')))
+ ->not->toContain('realtime_version')
+ ->not->toContain('realtime_image')
+ ->and(file_get_contents(app_path('Actions/Server/CleanupDocker.php')))
+ ->not->toContain('coolify-realtime')
+ ->not->toContain('realtimeImage')
+ ->and(file_get_contents(base_path('versions.json')))
+ ->not->toContain('"realtime"')
+ ->and(is_dir(base_path('docker/coolify-realtime')))->toBeFalse()
+ ->and(file_exists(base_path('.github/workflows/coolify-realtime.yml')))->toBeFalse()
+ ->and(file_exists(base_path('.github/workflows/coolify-realtime-next.yml')))->toBeFalse()
+ ->and($productionInstallScript)->not->toContain('LATEST_REALTIME_VERSION')
+ ->not->toContain('| Realtime')
+ ->and($nightlyInstallScript)->not->toContain('LATEST_REALTIME_VERSION')
+ ->not->toContain('| Realtime');
+});
diff --git a/tests/Pest.php b/tests/Pest.php
index d143e9c125..acc38329e7 100644
--- a/tests/Pest.php
+++ b/tests/Pest.php
@@ -79,8 +79,7 @@ beforeEach(function () {
// Flush the Server identity map cache to ensure tests get fresh data
Server::flushIdentityMap();
- // Browser Livewire actions often dispatch events; the Soketi host is not
- // resolvable from host-side Pest runs (docker DNS name coolify-realtime).
+ // Browser Livewire actions often dispatch events; disable broadcasting for host-side runs.
config(['broadcasting.default' => 'null']);
});
diff --git a/tests/Unit/Actions/Server/CleanupDockerTest.php b/tests/Unit/Actions/Server/CleanupDockerTest.php
index a70f07d15d..a74684e6e3 100644
--- a/tests/Unit/Actions/Server/CleanupDockerTest.php
+++ b/tests/Unit/Actions/Server/CleanupDockerTest.php
@@ -255,54 +255,34 @@ it('correctly excludes Docker Compose images from general prune', function () {
}
});
-it('excludes current version of Coolify infrastructure images from any registry', function () {
- // Test the regex pattern used to protect the current version of infrastructure images
- // regardless of which registry they come from (ghcr.io, docker.io, or no prefix)
+it('excludes current version of the Coolify helper image from any registry', function () {
$helperVersion = '1.0.12';
- $realtimeVersion = '1.0.10';
- // Build the exclusion pattern the same way CleanupDocker does
- // Pattern: (^|/)coollabsio/coolify-helper:VERSION$|(^|/)coollabsio/coolify-realtime:VERSION$
- $escapedHelperVersion = preg_replace('/([.\\\\+*?\[\]^$(){}|])/', '\\\\$1', $helperVersion);
- $escapedRealtimeVersion = preg_replace('/([.\\\\+*?\[\]^$(){}|])/', '\\\\$1', $realtimeVersion);
+ $escapedHelperVersion = preg_quote($helperVersion, '/');
+ $infraPattern = "(^|/)coollabsio/coolify-helper:{$escapedHelperVersion}$";
+ $pattern = "#{$infraPattern}#";
- // For PHP preg_match, escape forward slashes
- $infraPattern = "(^|\\/)coollabsio\\/coolify-helper:{$escapedHelperVersion}$|(^|\\/)coollabsio\\/coolify-realtime:{$escapedRealtimeVersion}$";
- $pattern = "/{$infraPattern}/";
-
- // Current versioned infrastructure images from ANY registry should be PROTECTED
$protectedImages = [
- // ghcr.io registry
"ghcr.io/coollabsio/coolify-helper:{$helperVersion}",
- "ghcr.io/coollabsio/coolify-realtime:{$realtimeVersion}",
- // docker.io registry (explicit)
"docker.io/coollabsio/coolify-helper:{$helperVersion}",
- "docker.io/coollabsio/coolify-realtime:{$realtimeVersion}",
- // No registry prefix (Docker Hub implicit)
"coollabsio/coolify-helper:{$helperVersion}",
- "coollabsio/coolify-realtime:{$realtimeVersion}",
];
- // Verify current infrastructure images ARE protected from any registry
foreach ($protectedImages as $image) {
expect(preg_match($pattern, $image))->toBe(1, "Current infrastructure image {$image} should be protected");
}
- // Verify OLD versions of infrastructure images are NOT protected (can be deleted)
$oldVersionImages = [
'ghcr.io/coollabsio/coolify-helper:1.0.11',
'docker.io/coollabsio/coolify-helper:1.0.10',
'coollabsio/coolify-helper:1.0.9',
- 'ghcr.io/coollabsio/coolify-realtime:1.0.9',
'ghcr.io/coollabsio/coolify-helper:latest',
- 'coollabsio/coolify-realtime:latest',
];
foreach ($oldVersionImages as $image) {
expect(preg_match($pattern, $image))->toBe(0, "Old infrastructure image {$image} should NOT be protected");
}
- // Verify other images are NOT protected (can be deleted)
$deletableImages = [
'nginx:alpine',
'postgres:15',
@@ -316,31 +296,19 @@ it('excludes current version of Coolify infrastructure images from any registry'
}
});
-it('protects current infrastructure images from any registry even when no applications exist', function () {
- // When there are no applications, current versioned infrastructure images should still be protected
- // regardless of which registry they come from
+it('protects current helper image from any registry even when no applications exist', function () {
$helperVersion = '1.0.12';
- $realtimeVersion = '1.0.10';
- // Build the pattern the same way CleanupDocker does
- $escapedHelperVersion = preg_replace('/([.\\\\+*?\[\]^$(){}|])/', '\\\\$1', $helperVersion);
- $escapedRealtimeVersion = preg_replace('/([.\\\\+*?\[\]^$(){}|])/', '\\\\$1', $realtimeVersion);
+ $escapedHelperVersion = preg_quote($helperVersion, '/');
+ $infraPattern = "(^|/)coollabsio/coolify-helper:{$escapedHelperVersion}$";
+ $pattern = "#{$infraPattern}#";
- // For PHP preg_match, escape forward slashes
- $infraPattern = "(^|\\/)coollabsio\\/coolify-helper:{$escapedHelperVersion}$|(^|\\/)coollabsio\\/coolify-realtime:{$escapedRealtimeVersion}$";
- $pattern = "/{$infraPattern}/";
-
- // Verify current infrastructure images from any registry are protected
expect(preg_match($pattern, "ghcr.io/coollabsio/coolify-helper:{$helperVersion}"))->toBe(1);
expect(preg_match($pattern, "docker.io/coollabsio/coolify-helper:{$helperVersion}"))->toBe(1);
expect(preg_match($pattern, "coollabsio/coolify-helper:{$helperVersion}"))->toBe(1);
- expect(preg_match($pattern, "ghcr.io/coollabsio/coolify-realtime:{$realtimeVersion}"))->toBe(1);
- // Old versions should NOT be protected
expect(preg_match($pattern, 'ghcr.io/coollabsio/coolify-helper:1.0.11'))->toBe(0);
expect(preg_match($pattern, 'docker.io/coollabsio/coolify-helper:1.0.11'))->toBe(0);
-
- // Other images should not be protected
expect(preg_match($pattern, 'nginx:alpine'))->toBe(0);
});
diff --git a/tests/Unit/ProductionImageWorkflowTest.php b/tests/Unit/ProductionImageWorkflowTest.php
index 2c29fe55be..9c6e210651 100644
--- a/tests/Unit/ProductionImageWorkflowTest.php
+++ b/tests/Unit/ProductionImageWorkflowTest.php
@@ -72,7 +72,6 @@ it('runs support image workflows from main', function (string $workflowFile) {
->not->toContain('v4.x');
})->with([
'helper' => 'coolify-helper.yml',
- 'realtime' => 'coolify-realtime.yml',
]);
it('prevents the stable helper workflow from publishing an existing version', function () {
@@ -90,23 +89,6 @@ it('prevents the stable helper workflow from publishing an existing version', fu
->toContain('cancel-in-progress: false');
});
-it('prevents the stable realtime workflow from publishing an existing version', function () {
- $workflow = file_get_contents(dirname(__DIR__, 2).'/.github/workflows/coolify-realtime.yml');
-
- expect($workflow)
- ->toContain('workflow_dispatch:')
- ->toContain('- config/constants.php')
- ->toContain('check-version:')
- ->toContain('needs: check-version')
- ->toContain('php bootstrap/getRealtimeVersion.php')
- ->toContain('VERSION="${BASE_VERSION}"')
- ->toContain('docker buildx imagetools inspect "$IMAGE"')
- ->toContain('Version $VERSION already exists in $registry')
- ->toContain('Version $VERSION is available in both registries')
- ->toContain('Could not verify $IMAGE')
- ->toContain('cancel-in-progress: false');
-});
-
it('generates the production changelog from main', function () {
$workflow = file_get_contents(dirname(__DIR__, 2).'/.github/workflows/generate-changelog.yml');
diff --git a/versions.json b/versions.json
index 6eb14d45e8..7262de886a 100644
--- a/versions.json
+++ b/versions.json
@@ -9,9 +9,6 @@
"helper": {
"version": "1.0.17"
},
- "realtime": {
- "version": "1.0.20"
- },
"sentinel": {
"version": "1.0.1"
}