Enabling the EspoCRM WebSocket for real-time updates

EspoCRM pushes live notifications to open browser sessions through a WebSocket daemon that needs its own process, a proxy route and a matching Docker or host setup. This page explains how the parts fit, what to confirm before you switch it on, and what the work involves.

On this page

Why an EspoCRM WebSocket setup is more than a checkbox

Sales and service staff expect a new assignment, a changed record or a notification to appear on screen without a page refresh. In EspoCRM, that behavior depends on a separate WebSocket daemon running beside the application, so enabling it is an infrastructure decision as much as an application setting. Once it is live, users see updates arrive as they happen, which changes how a queue, a shared opportunity or a case is worked. Before committing, decide which teams actually depend on live updates. Dispatchers and service queues usually benefit most, while a team that works from scheduled reports may not notice the difference.

The feature is not a single flag for three reasons. First, the WebSocket process runs as its own service, so something must start it, keep it running and restart it after a reboot, which is why the topic covers running websocket.php under systemd. Second, the reverse proxy in front of EspoCRM must pass WebSocket upgrade requests through to that process. A proxy path that works for normal HTTP can still block the upgrade, and the symptom is often that updates silently fail to arrive. Third, real-time messaging relies on a ZMQ extension in PHP, so the runtime needs that component installed and matched to the server, and the Docker setup changes how these pieces are wired together.

Keep polling-style refresh when your user count is small, when the proxy or hosting platform cannot pass WebSocket traffic cleanly, or when your operations team cannot yet monitor an extra long-running process. Enable the daemon when the business case depends on instant awareness and you can own its uptime. Confirm the exact ZMQ package names, daemon commands, proxy directives and Docker settings against the EspoCRM documentation for your installed version, since these details change between releases.

Which WebSocket setup fits your hosting method

This table compares the three paths for enabling the EspoCRM WebSocket: a host install behind Nginx, a host install behind Apache, and the Docker setup. Read each row against your current hosting, then use the confirmation column to check what your environment must support before you pick a path.

PathMoving partsTypical ownerConfirm before choosing
Host install behind NginxZMQ extension for PHP, websocket.php run as a long-lived service, and a proxy location block forwarding WebSocket upgrade requests to the daemonLinux platform or web team that already runs Nginx and PHP-FPMYour Nginx version supports WebSocket proxying, the ZMQ extension is available for your PHP build, and your service manager can keep the daemon running
Host install behind ApacheZMQ extension for PHP, websocket.php run as a long-lived service, and proxy or rewrite rules that upgrade the connection to the daemonTeam that already operates Apache with mod_rewrite and .htaccess handlingRequired Apache proxy and WebSocket modules are enabled, rewrite rules do not conflict with EspoCRM's own rules, and the daemon is supervised by systemd or an equivalent
Docker setupDaemon container running websocket.php alongside the application and database containers, with the reverse proxy routing WebSocket traffic to that containerPlatform or DevOps team that manages the Compose stack and the public entry pointThe Compose file includes the daemon service in your EspoCRM version, your edge proxy forwards upgrade requests to it, and your change process covers rebuilds
Daemon supervisionProcess that must restart on failure and start at boot, with logs captured where your team reads themOperations team that owns service monitoringYour standard for service restarts, log retention and alerting is applied to the WebSocket process, not only to the web server
Proxy and TLSPublic WebSocket endpoint behind the same TLS certificate as the CRM, with upgrade headers passed throughSecurity or network team that owns certificates and firewall rulesCertificates cover the hostname users reach, load balancers pass upgrade headers, and firewall rules allow only the intended internal path
Client connectivityBrowsers open a persistent connection, which may be blocked by corporate proxies or strict egress rulesNetwork team and help deskUsers on the networks you serve can complete the upgrade handshake, and a fallback behavior is acceptable if the connection drops
Scaling and multiple nodesA single daemon instance per installation is the typical arrangement, so load balancers need sticky or dedicated routingArchitect who plans high availability for the CRMYour EspoCRM version and documentation describe supported multi-node behavior before you add application nodes
Upgrades and rebuildsExtension, PHP and container image changes can affect the daemon and its configurationRelease owner for EspoCRMEach upgrade is tested with the WebSocket enabled, and the test covers reconnection after the daemon restarts
VerificationNotifications arrive in a second browser session without a page refresh, and the daemon log shows connectionsQA or the CRM administratorYou have a written test that confirms real-time delivery through the same public path your users take

The order that avoids silent failures

The sequence matters because each layer hides the failure of the one below it. Confirm that EspoCRM already works over HTTPS before you touch the WebSocket. The login page, the record views and the scheduled jobs all need to be healthy first, because the real-time feature depends on the same application, the same database and the same public hostname. Check that the background job runner is scheduled (cron on Linux, Task Scheduler on Windows) and that queued jobs actually run, since a broken scheduler is easy to miss when the browser pages load normally. Only then should you move on to the messaging layer.

Next, install and configure the messaging extension, then start the daemon. The daemon can only publish events that the application has been told to send through the configured messaging backend, so a daemon running with no extension, or with settings that do not match the config.php values, produces no errors in the browser and no notifications either. Check the daemon's own log output and confirm the configuration keys match what the application reads. Treat a daemon that starts cleanly as a process check only, not as proof that events flow.

The proxy comes last, and a browser test means nothing until it passes the upgrade headers. Confirm that the reverse proxy forwards the WebSocket upgrade request to the daemon's port and keeps the connection open longer than a typical page request. A half-finished setup often looks healthy on the login page because plain HTTP requests succeed, while the socket handshake quietly fails and the page falls back to no live updates. Test with two browser sessions logged in as different users, create or change a record in one, and watch the other. If the update only appears after a manual refresh, stop and check the proxy and daemon logs before changing anything else.

How to enable the WebSocket daemon step by step

This sequence takes a working EspoCRM installation to a state where record changes appear in other open browser sessions without a page reload. Each step ends with a check you can run before moving on, so problems surface in the step that caused them.

  1. Confirm the base installation and background jobs

    Before touching the WebSocket, confirm that EspoCRM loads over HTTPS, that you can sign in as a non-admin user, and that background jobs run. Background jobs depend on cron on Linux hosts or a scheduled task on Windows, and the server configuration documentation lists the PHP and database versions your release supports. Check the scheduled job log in the administration area and confirm that jobs are executing. The step is done when the application is stable and scheduled jobs are running, because real-time features are easier to diagnose on a clean base.

  2. Install and configure the ZMQ extension

    Install the PHP ZeroMQ extension on the application server and confirm it is loaded for the same PHP version and SAPI that serve EspoCRM. Then enable the WebSocket in the administration settings and set the connection values the documentation describes for your version, including the internal port and the public address that browsers will use. Confirm each key name and file path against the official documentation for your EspoCRM version, since those details are not covered here. The check is that the PHP module list includes the ZeroMQ extension and that the settings save without error.

  3. Start websocket.php under a supervisor

    Run the WebSocket script that ships with EspoCRM as a long-running process. On a host, define a systemd unit that runs the script with PHP from the EspoCRM directory, runs it as the same user that owns the application files, and restarts on failure. In Docker, run the same script in a dedicated container that shares the EspoCRM code volume and uses the same configuration. Confirm the exact command and unit options against the documentation for your version. The check is that the service reports active, the port is listening on the internal interface, and the process survives a restart of the unit or container.

  4. Add the WebSocket proxy route

    Add a location block in Nginx or a proxy rule in Apache that forwards the WebSocket path from the public hostname to the internal port where websocket.php listens. The route must pass the Upgrade and Connection headers and must use HTTP/1.1 to the upstream. Keep the TLS configuration of the main site, and confirm the path and header handling in the documentation for your version and web server. Reload the web server after validating its configuration syntax. The check is that a WebSocket handshake to the public path returns a switching protocols response rather than a 404 or 502.

  5. Test with two browser sessions

    Sign in to EspoCRM as two different users in separate browser sessions, ideally one in a private window. Open the same record in both sessions, then edit a field and save it from the first session. The second session should show the update or a notification without a manual refresh. If it does not, check the browser developer tools for the WebSocket connection status and the server logs for the daemon. The step is done when the change appears in the second session within the time you expect for your setup, and the connection stays open while the page is idle.

  6. Verify restart behavior and record the configuration

    Restart the web server, the WebSocket service and the PHP-FPM service in turn, then repeat the two-session test. Confirm that the daemon reconnects automatically and that background jobs still run after the restarts. Record the systemd unit or Compose service definition, the proxy configuration, the PHP extension version and the settings you changed, so that a future upgrade or server move can reproduce the setup. The step is done when the test passes after each restart and the configuration is stored in your change management system.

Nginx, Apache or Docker: how the proxy path differs

On an Nginx host, the WebSocket daemon sits behind its own location block that proxies to the port the daemon listens on. The main application location handles ordinary HTTP requests, so the WebSocket path needs separate handling. Nginx forwards a client's protocol upgrade only when that location explicitly passes the upgrade and connection headers, which is the most common point of failure.

  • Upgrade headers: The location must pass the Upgrade and Connection headers from the client to the daemon. Without them the handshake fails and the browser stays disconnected.
  • Idle timeouts: Raise the proxy read and send timeouts for the WebSocket location above the defaults so idle sockets are not closed mid-session. Confirm the values against your Nginx version and the daemon's keep-alive behavior.
  • TLS and the wss scheme: Browsers on an HTTPS site connect with wss://. The certificate must cover the same hostname, and mixed content rules block ws:// connections from an HTTPS page.
  • Path and upstream match: The location path must match the path the EspoCRM client requests, and the upstream must point to the daemon's listening port.

A typical failure looks like this: the EspoCRM page loads, but real-time notifications never arrive, and the browser console shows a failed handshake or a socket that closes after a fixed interval.

Check the browser developer tools to confirm the handshake returns the switching protocols status and that the socket stays open through a period of inactivity longer than your proxy timeout.

Protecting the socket path and the daemon process

The WebSocket adds a public path and a long-running process to an EspoCRM deployment, and both need the same care as the web application itself. The cards below cover the socket route, the daemon's account and restart behavior, the messaging channel's network reach, version currency, and health monitoring.

Publish the socket path over TLS only

The browser opens the WebSocket on a path your reverse proxy forwards to the daemon, so that path is a new public entry point beside the main site. Serve it over HTTPS only, and check that the upgrade request and the socket connection both arrive encrypted in your proxy configuration. Confirm that the certificate on the socket path is the same managed certificate that covers the CRM host, and that no plain HTTP listener forwards to the daemon.

Run the daemon as a non-privileged account

The websocket.php process should run under the same unprivileged account that owns the EspoCRM files, not root and not a shared administrator login. Give that account read access to the application and write access only to the directories it must write to. Configure systemd to restart the service on failure, so a crashed daemon does not silently stop pushing notifications while users still see a working CRM.

Limit the messaging channel on the network

The ZMQ channel between EspoCRM and the daemon should be reachable only from the application host and the daemon host. Bind it to a loopback or private interface and block it at the host firewall, so it is never exposed through the public proxy or to other network segments. Confirm the bind address in your ZMQ configuration after each change, because a default bind to all interfaces is easy to miss.

Keep the extension and EspoCRM aligned

The WebSocket depends on the ZMQ extension, the PHP build and the EspoCRM release running together, so upgrading one can break the others. Track the supported PHP versions and the current EspoCRM release line before each change, and retest real-time notifications after every upgrade. Remember that upgrading through the UI is disabled by default as of version 10.0, so plan upgrades through your change process rather than through an admin screen.

Monitor daemon health and logs

A stopped daemon fails quietly, so add a check that confirms the service is active and that the socket accepts connections. Route the daemon's logs to your central logging system and alert on repeated restarts or connection errors. Document who responds to these alerts and what the first checks are, such as the systemd status, the proxy error log and the ZMQ bind state.

Set session and IP limits around the socket

The WebSocket does not add its own authentication controls, so access still depends on EspoCRM's login, session and network settings. Review the auth token lifetime and consider IP restriction for admin and staff access, as the EspoCRM security guidance recommends. Confirm in testing how a session expiry or an IP block affects an open socket connection, and record the behavior so support staff know what users will see.

What enabling EspoCRM real-time updates costs and needs from your team

What drives the effort of enabling the EspoCRM WebSocket?

The effort depends mainly on how EspoCRM is hosted, how many layers sit between users and the application, and how many environments need the change. A bare-metal or VM install with Nginx or Apache needs a daemon under systemd and a proxy location for the WebSocket path. A Docker Compose stack needs the daemon container and the proxy rules wired to it. Each reverse proxy, TLS terminator or load balancer in front of EspoCRM adds a configuration point to verify. Work also grows with the testing scope: checking live notifications across browsers, sessions and user roles takes longer than confirming the daemon starts. Ask any partner to break the quote down by hosting method, proxy path, environment count and test cases.

Can our own team enable the EspoCRM WebSocket without a partner?

Yes, if your team already runs PHP applications behind Nginx, Apache or Docker and can manage a systemd service. The core steps are installing the ZMQ extension, enabling the WebSocket settings in EspoCRM, running websocket.php as a service, and proxying the WebSocket connection through your web server. Teams without that background usually spend the most time on proxy upgrade headers and on confirming that the connection survives TLS termination. A partner is useful when you need the change tested across several environments, documented for the next administrator, or delivered inside a fixed scope with written acceptance checks.

What does the work need from our side before it starts?

Plan for four inputs. First, administrative access to the EspoCRM host or Docker host, including the ability to create a systemd unit or edit the Compose file. Second, a non-production test environment with a copy of your EspoCRM configuration, so the change can be verified without affecting users. Third, a named owner for the reverse proxy and TLS certificates, because the WebSocket route must be added to that layer and the owner must approve it. Fourth, a list of the user groups and browsers that need live updates, so testing covers the real use. Confirm each of these with your own environment before requesting a quote.

How does enabling the WebSocket change during an EspoCRM upgrade?

Upgrades can affect the WebSocket in two ways. The daemon runs from the EspoCRM installation, so a new release may need the service restarted or its configuration checked afterward. Proxy rules that worked for one version can also need review if the connection path or related settings change. Check the release notes for each target version before the upgrade, confirm that the ZMQ extension still matches the PHP version in use, and repeat the live notification test after the upgrade. The EspoCRM upgrade process should include these checks in the same change window, not as a later task.

What should we check when notifications stop after a server change?

Start with the daemon, then the proxy, then the browser. Confirm that the websocket.php process is running under systemd and that its logs show no startup errors. Check that the ZMQ extension is loaded in the PHP version the daemon uses, since a PHP upgrade can load a different binary. Next, confirm that the proxy forwards the WebSocket upgrade headers and that the path matches the EspoCRM configuration, including any changed hostname or certificate. Finally, check the browser console for failed connections and confirm the user is signed in on the expected domain. Record each finding so the next change has a checklist.

How do we ask for a fixed-scope quote for this work?

Send a written description of your environment and ask the provider to quote against it. Include the EspoCRM version, PHP version, database engine, hosting method (bare metal, VM, Docker Compose), the web server or reverse proxy in front of EspoCRM, the number of environments, and whether a test environment exists. Ask for the deliverables in writing: the configuration changes, the systemd unit or Compose changes, a verification checklist, and handover notes. Also ask what is excluded, such as later upgrades, other proxies or additional testing. Fixed-scope engagements are agreed in writing before work starts, so the quote should list acceptance checks that both sides can run.

What to confirm in your environment before you switch it on

Real-time updates depend on more than a setting in EspoCRM. The version, the runtime stack, the messaging extension, the proxy, the process supervisor and the network path each have to agree before the daemon sends its first message. Confirm each item against the vendor documentation or your own change process before you schedule the change.

EspoCRM version and feature match

Confirm that the EspoCRM release you run includes the WebSocket feature and that the extension you plan to install is built for that same release. Check the releases page for the version you target, and do not assume a point release on one branch matches a different major line. Record the exact version in your change ticket so the daemon, the core files and the extension can be rolled back together if an upgrade goes wrong.

PHP and database versions

Check the server configuration documentation for the supported PHP range and the minimum database versions for MySQL, MariaDB or PostgreSQL. The WebSocket daemon runs on the same PHP runtime as the application, so a PHP build missing a required module will fail the daemon even when the web application loads. Confirm that the CLI binary your supervisor calls is the same version as the one serving web requests.

Messaging extension availability

Confirm that the messaging extension used for WebSocket delivery is available for your install method and that your organization may install it. Check whether your package source, air-gapped mirror or container image includes the required native libraries, and whether your security team has approved the extension. Without this check, the daemon may not start, and teams may assume real-time updates are working when only polling is active.

Proxy handling of long-lived connections

Confirm how your reverse proxy or load balancer treats WebSocket upgrade requests. Look for the upgrade headers, idle timeouts that close quiet connections, buffering settings and any health check that opens and closes connections too often. A proxy that accepts the upgrade but drops the connection after a fixed idle period will produce intermittent missing updates that are hard to trace back to the daemon.

Process supervisor or container platform

Confirm that your process supervisor or container platform can run the daemon as a long-lived service with automatic restart, log capture and a defined run user. Check that the service account can read the EspoCRM configuration without gaining write access to the whole application tree. If you run containers, confirm that the daemon container has its own health signal rather than relying on the application container being healthy.

Firewall and network policy

Confirm that your firewall, security groups and network policy allow the path from browsers to the proxy on the WebSocket port, and that the daemon's internal port is reachable only from the proxy. Review whether any inspection appliance or corporate web filter blocks WebSocket traffic, because some do so silently. Record each rule in your change ticket so reviewers can confirm the daemon is not exposed directly to the internet.

How DeployOpen scopes and delivers EspoCRM real-time setup

DeployOpen plans, implements, tests and documents the WebSocket setup for EspoCRM inside your own infrastructure, whether that is a Linux server, a Docker host or a fixed-scope environment you control. The work starts with a written scope that names the hosting model, the proxy and the verification steps, so you know exactly what gets delivered before any change is made.

How we scope

  • Confirm your hosting model first: bare metal or VM with Nginx or Apache, or a Docker Compose stack.
  • Record the EspoCRM version, PHP version, database engine and the web server already in use.
  • Agree in writing which browsers, users and notification types must work in real time before build.

How we build

  • Install and configure the ZMQ extension, then run websocket.php as a supervised systemd service under a dedicated account.
  • Proxy the WebSocket path through your Nginx or Apache virtual host, with TLS and upgrade headers tested end to end.
  • Build the Docker variant with its own daemon container, network path and reverse proxy rules, matched to your existing stack.

How we hand over

  • Test restart behavior, reconnection after a proxy reload and recovery after a server reboot, then record the results.
  • Provide a runbook covering service names, log locations, configuration keys and the checks your operators should repeat.
  • Walk your platform and administration staff through the setup so they can troubleshoot without us.

How we support

  • Engagements are fixed-scope, so changes after go-live are scoped and quoted separately in writing.
  • Ongoing support, upgrades and retesting after EspoCRM or proxy updates are available as a retainer.
  • Confirm with DeployOpen during scoping which support hours, response paths and upgrade coverage a retainer includes.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.