Migrate realtime services to Reverb
New Coolify releases run Laravel Reverb and the web terminal server inside the main coolify container. They no longer use the separate coolify-realtime container.
Most installations do not need a manual change. Review your configuration before the update if you use a custom Compose override, custom realtime ports, a firewall, or a Cloudflare Tunnel.
The update accepts a soketi override in docker-compose.custom.yml. Existing proxy routes and port settings remain compatible. You can move custom port bindings to coolify to make the override reflect the new container layout.
What changes
| Before | After |
|---|---|
Soketi listens in coolify-realtime | Reverb listens in coolify |
The terminal server listens in coolify-realtime | The terminal server listens in coolify |
The proxy sends realtime traffic to coolify-realtime:6001 | The proxy sends realtime traffic to coolify:6001 |
The proxy sends terminal traffic to coolify-realtime:6002 | The proxy sends terminal traffic to coolify:6002 |
The external paths do not change:
/app/*carries browser WebSocket connections./apps/*carries Pusher-compatible API requests./terminal/wscarries web terminal connections.
The update keeps the existing Pusher application ID, key, and secret. It also keeps SOKETI_PORT as the compatible Docker host-port setting. Do not rename that variable during this migration.
The update script also removes the old coolify-realtime container. If .env still contains PUSHER_BACKEND_HOST=coolify-realtime, the script changes it to 127.0.0.1, because Reverb now runs in the same container as Coolify.
The coolify container also has coolify-realtime as a network alias on the coolify Docker network. A reverse proxy that still sends traffic to coolify-realtime:6001 or coolify-realtime:6002 keeps working.
Before you update
Back up the instance configuration
cd /data/coolify/source
cp .env .env.before-reverb
if [ -f docker-compose.custom.yml ]; then
cp docker-compose.custom.yml docker-compose.custom.yml.before-reverb
fiCheck for a Soketi service override
grep -nE '^[[:space:]]*soketi:' docker-compose.custom.yml 2>/dev/null || trueIf the command prints a line, review the override. Migrating it as shown below is optional; legacy soketi overrides are still accepted.
Record custom realtime settings
grep -E '^(PUSHER_HOST|PUSHER_PORT|PUSHER_SCHEME|PUSHER_BACKEND_PORT|SOKETI_PORT|TERMINAL_PORT)=' .env || trueKeep this output until you finish the verification.
Migrate a custom Compose override
The old firewall example configured ports on two services:
services:
coolify:
ports: !override
- "127.0.0.1:${APP_PORT:-8000}:8080"
soketi:
ports: !override
- "127.0.0.1:${SOKETI_PORT:-6001}:6001"
- "127.0.0.1:6002:6002"Move all three bindings to the coolify service:
services:
coolify:
ports: !override
- "127.0.0.1:${APP_PORT:-8000}:8080"
- "127.0.0.1:${SOKETI_PORT:-6001}:6001"
- "127.0.0.1:6002:6002"The web terminal always uses host port 6002. TERMINAL_PORT does not change the Docker host port.
If your override removed all public bindings, replace this:
services:
coolify:
ports: !override []
soketi:
ports: !override []with this:
services:
coolify:
ports: !override []Move only port bindings that are still required. Remove Soketi-specific image, command, environment, health-check, and volume settings. Remove the soketi service block when it is empty.
Keep ports 8000, 6001, and 6002 reachable until the dashboard, realtime updates, and terminal work through your domain. You can restrict them after you complete the verification.
Check the environment variables
The variables have different purposes:
| Variable | Purpose |
|---|---|
SOKETI_PORT | Compatible Docker host-port override for origin port 6001 |
REVERB_PORT | Optional. Takes precedence over SOKETI_PORT for the Docker host port of origin port 6001. You do not need it when you already use SOKETI_PORT. |
PUSHER_PORT | Public port used by the browser |
PUSHER_BACKEND_PORT | Internal Reverb listen port, normally 6001 |
PUSHER_BACKEND_HOST | Host that Coolify uses to send events to Reverb, normally unset or 127.0.0.1 |
TERMINAL_PORT | Public port used by the browser for the web terminal, for example 443 behind a reverse proxy. It does not change the Docker host port, which is always 6002. |
Do not change an existing SOKETI_PORT value. Existing firewall rules and port forwarding can depend on it.
For a dashboard behind Cloudflare, the public browser port is normally 443:
PUSHER_PORT=443
PUSHER_BACKEND_PORT=6001Do not set PUSHER_PORT=6001 for a Cloudflare-proxied hostname. Port 6001 is the origin port. The browser connects to Cloudflare on port 443.
If you do not have an explicit PUSHER_PORT, leave it unset. Coolify selects the public port from the dashboard request and keeps direct IP access compatible.
Cloudflare configurations
Dashboard through the Coolify proxy
This is the recommended configuration. Send the dashboard hostname to the Coolify proxy on port 80 or 443. The generated proxy configuration routes:
/app/* -> coolify:6001
/apps/* -> coolify:6001
/terminal/ws -> coolify:6002
/* -> coolify:8080You do not need separate Cloudflare routes for Reverb or the terminal.
For a Cloudflare Tunnel that terminates TLS at Cloudflare, set the tunnel service URL to http://localhost:80. For end-to-end TLS, use the HTTPS origin configuration from the Full TLS guide.
Separate realtime hostname
Older tunnel configurations can use a separate hostname:
| Public hostname or path | Tunnel service |
|---|---|
coolify.example.com | http://localhost:8000 |
coolify.example.com/terminal/ws | http://localhost:6002 |
coolify-realtime.example.com | http://localhost:6001 |
This remains compatible. Keep:
PUSHER_HOST=coolify-realtime.example.com
PUSHER_PORT=443
PUSHER_BACKEND_PORT=6001The Cloudflare route still connects to origin port 6001, but Reverb now handles that port in the coolify container.
Update
Update Coolify from Settings > Updates. Existing realtime routes, port settings, and legacy soketi overrides remain compatible. Keep the configuration backups until you have verified the dashboard, realtime updates, and terminal.
If you choose to migrate an override manually, check that all required port bindings are now on coolify. Review the update log in /data/coolify/source/upgrade-*.log if the update reports a configuration error.
Verify the migration
Run these checks after the update:
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
docker logs --tail 100 coolifyConfirm that:
coolify,coolify-db, andcoolify-redisare running.- The
coolify-realtimecontainer is gone. The update removes it. - The dashboard loads through its normal URL.
- The browser developer tools show a successful WebSocket request to
/app/.... - The WebSocket request uses
wssand public port443when Cloudflare serves the dashboard over HTTPS. - A deployment or status change appears in the dashboard without a page refresh.
- The web terminal connects through
/terminal/ws.
You can also open /realtime in two browser tabs and send a test event.
Troubleshooting
The coolify container stays unhealthy
The container healthcheck now includes Reverb. Check the Reverb log inside the container and confirm that nothing else listens on port 6001:
docker exec coolify curl --fail http://127.0.0.1:6001/up
sudo ss -tulpn | grep :6001The dashboard keeps working while the container is unhealthy. Only realtime updates stop.
Cloudflare returns an error for the WebSocket request
- Confirm the browser connects to public port
443, not origin port6001. - Confirm Cloudflare WebSockets are enabled for the zone.
- Confirm the tunnel or proxy route includes
/app/*. - Confirm the Coolify proxy can reach
coolify:6001on thecoolifyDocker network.
The dashboard works but realtime updates do not
Check PUSHER_HOST and PUSHER_PORT in /data/coolify/source/.env. Remove obsolete overrides when the dashboard and Reverb use the same hostname, or keep port 443 for a separate Cloudflare realtime hostname.
Also confirm that PUSHER_BACKEND_HOST is unset or 127.0.0.1. A public hostname in that variable sends server-side events to the wrong place.
Direct IP access stops receiving updates
Confirm that the coolify container publishes host port ${REVERB_PORT:-${SOKETI_PORT:-6001}} to container port 6001 and host port 6002 to container port 6002. Also confirm that the server firewall permits these host ports from your client address.
