EspoCRM Nginx configuration on Ubuntu

A guide to running EspoCRM on Nginx and PHP-FPM on Ubuntu, covering PHP modules, the server block, upload and timeout settings and denying access to internal directories.

On this page

Why EspoCRM on Nginx needs a deliberate server block

Running EspoCRM on Nginx on your own Ubuntu servers works well when the web server exposes only what the application needs and nothing else. The server block is the access boundary: it decides which files a browser can reach, how large uploads may be, how long requests may run, and which paths return nothing. Most of the risk in this setup comes from a default block that serves the whole application directory, so the first task is to point the document root at the public directory and treat everything above it as private. The server configuration docs list PHP 8.3 to 8.5, MySQL 8.0 or newer, MariaDB 10.6 or newer or PostgreSQL 15, with Nginx and PHP-FPM as the web tier. Confirm the exact PHP modules and database version against the EspoCRM server configuration docs before you build the host, because the list changes between releases.

Four kinds of content must stay private: configuration files holding database credentials and application settings, the data and cache directories, the vendor and internal library code, and client-side source that is not meant to be fetched directly. The server block should deny direct requests to those paths and send everything else through the front controller. Background jobs are a separate concern that the web server cannot handle: EspoCRM needs cron (or an equivalent scheduled task) to run them, and a missing cron entry looks like a healthy site with stalled email, workflows and imports. Also decide early whether you will use the Ubuntu installation script, which deploys a Docker-based stack with Nginx and MariaDB and can request Let's Encrypt certificates, or build the host by hand. The script trades control over package versions and file layout for a faster start, and the choice affects every later step.

Bring in outside help when the platform team lacks PHP-FPM tuning experience, when the server must sit behind an existing reverse proxy or in a restricted network, or when the instance will hold regulated customer data and the access rules need review. A practical scope to request from any partner is a written review of the server block against your directory layout, a test plan that proves private paths return denial, and a backup and restore check that includes the database and uploaded files. Ask for those items in the written scope, since they determine whether the configuration is verified or only copied from an example.

Which Nginx deployment path fits your team

This table compares the Ubuntu installation script, which deploys a Docker stack with Nginx and MariaDB, against a native Nginx and PHP-FPM install on the host. Read each row as a question about who will own PHP versions, upgrades, backups and the server block after go-live. The main takeaway is that the script trades control for a faster, more opinionated setup, while the native path gives your team full ownership of every layer.

Decision areaUbuntu installation scriptNative Nginx and PHP-FPM
Setup starting pointDocker stack with Nginx and MariaDB deployed by the installerNginx, PHP-FPM, database and EspoCRM installed directly on Ubuntu
PHP version controlSet by the stack image, so confirm the version against the server configuration docs before go-liveYour team chooses the PHP version from the supported range and manages the packages
Server block ownershipGenerated and managed inside the stack, so custom location rules need careYour team writes and maintains the server block, including upload and deny rules
Upgrade handlingUses the command.sh utility for upgrades, so confirm the steps for your target versionUpgrades follow the EspoCRM upgrade process and your own package and PHP changes
Backup toolingcommand.sh provides backups and restores, so confirm what it covers in your setupBackups are built from your own database dump and file copy routines
Optional TLSLet's Encrypt certificates can be enabled during installationCertificates are issued and renewed through your own tooling
Best fitSmall teams that want a documented starting point and accept the stack's defaultsTeams with existing Nginx standards, custom PHP needs or strict change control
Who keeps it runningShared between your team and the stack's maintainers, so agree responsibilities in writingYour platform team, with a partner if you choose to outsource the work

How the EspoCRM server block separates public and private paths

The most important rule in the EspoCRM Nginx server block is that the document root must point at the public directory of the EspoCRM installation, not at the application root. Only the public directory is meant to be reachable from a browser. Everything else, including configuration files, the vendor libraries, source code and the data that EspoCRM writes during operation, should sit outside what Nginx serves. Requests for application routes should be passed to index.php through a try_files rule, so that the front controller handles them and static files are served directly when they exist. Confirm the exact routing block against the server configuration documentation for the EspoCRM version you deploy, because the expected rules can change between releases.

Pointing the root at the public directory does not, by itself, block the internal folders if they are reachable through a path that the server still resolves. For that reason the block should carry explicit deny rules for the client and internal directories that EspoCRM uses to store runtime data, logs, cache and uploads. Test each rule after deployment by requesting the protected paths directly and confirming that Nginx returns a denial rather than file contents. Also verify that PHP files outside the front controller are not executed from locations that accept user uploads. Keep the list of denied paths under version control so that an upgrade does not silently drop a rule.

Two directives govern how much data a request can carry and how long it can run. The client body size limit, set with client_max_body_size, must be large enough for the attachments your teams upload, and the PHP upload and post size limits in the PHP configuration must match it or uploads will fail with an unhelpful error. Read and send timeouts in Nginx and the PHP-FPM request timeout need to allow for slow responses without being so long that they hide a stuck process. Large CSV imports are the main case where these limits are tested. The import documentation describes running large files through cron in idle execution rather than in one long web request, so the browser request does not have to stay open while thousands of rows are processed. Plan the cron schedule and the timeouts together, and confirm the cron job runs as the web server user with the same PHP version.

Setting up EspoCRM on Nginx and PHP-FPM step by step

This sequence takes a clean Ubuntu server to a running EspoCRM instance behind Nginx and PHP-FPM, with the public directory as the only web root, internal paths blocked, uploads sized correctly and background jobs confirmed. Each step ends with a check so problems are caught before the next layer is added.

  1. Confirm the server and choose the stack versions

    Your platform engineer confirms the Ubuntu release, the PHP version, the database engine and the Nginx package you plan to run. The EspoCRM server configuration docs list supported PHP versions (8.3 to 8.5), MySQL 8.0 or newer, MariaDB 10.6 or newer, or PostgreSQL 15, and they list Nginx as a supported web server. Record the chosen versions in your change ticket. Done when every component is on the supported list and you have a written version baseline to test against later.

  2. Install PHP-FPM and the required PHP modules

    Install PHP-FPM for the chosen PHP version, then add the extensions listed in the EspoCRM server configuration docs. Confirm the exact module names against that page, because package names differ between Ubuntu releases and PHP repositories. Set the PHP-FPM pool to run under the Nginx user and enable the service. Done when php -m lists every required module and systemctl status php-fpm (with your version in the unit name) shows the service active.

  3. Install and secure the database

    Install MariaDB or MySQL, or PostgreSQL, at a version the docs support. Create a dedicated database and a application user limited to that database, and set a strong password stored outside the web root. Restrict network binding to localhost unless your architecture needs otherwise. Done when you can log in as the application user from the server and the same login fails for any other database.

  4. Deploy the EspoCRM files

    Download the EspoCRM release package from the official GitHub releases page or the installation documentation, unpack it into a directory such as /var/www/espocrm, and keep the full tree outside any public path except the public subdirectory. Verify the archive checksum where the project publishes one. Done when the directory contains the application files and a public folder, and your team has recorded the release version being deployed.

  5. Write the Nginx server block with deny rules

    Create a server block whose root points to the public directory, not the application root. Pass PHP requests to the PHP-FPM socket and deny direct access to internal directories such as data, custom, application and vendor paths, following the rules in the server configuration docs. Enable the site, run nginx -t, and reload. Done when the syntax test passes, the home page loads, and a direct request to a blocked internal path returns a denied response rather than file content.

  6. Set upload size and timeouts

    Set the Nginx body size limit and the PHP upload and post limits so they accept the largest attachment or CSV import you expect, then set read and send timeouts that cover slow imports and report generation. Keep these values aligned with the limits in your PHP configuration. Confirm the exact directive names and recommended values in the official server configuration docs. Done when a test upload near your intended limit succeeds and one above it fails with a clear error.

  7. Set file ownership and permissions

    Assign the application tree to the PHP-FPM user and grant write access only to the directories EspoCRM must write to, such as data, custom and upload locations. Keep the rest read-only for the web user. Follow the permission guidance in the server configuration docs and reapply it after every upgrade. Done when the installer can write its files, and a test write to a read-only application file from the web user fails.

  8. Schedule the cron job and verify the install

    Add the EspoCRM cron entry for the web user so background jobs run on schedule, as the server configuration docs require. Then open the install page in a browser through the new server block and complete the setup wizard. After login, check the administration job queue and confirm a scheduled job has run. Done when the install wizard completes, the admin area loads without errors, and the job log shows recent cron execution.

Security settings to apply in the Nginx layer

EspoCRM's own security settings govern accounts, sessions and authentication, while Nginx decides who can reach the application at all. The cards below cover the EspoCRM-side controls that pair with the Nginx layer, and the checks that keep both in line after every change.

Restrict access by IP address

EspoCRM's security documentation recommends restricting access by IP address. Where your staff work from known networks, put the allowlist in Nginx with allow and deny rules so requests from other networks never reach PHP. Confirm with your network team whether remote staff, VPN egress addresses and the customer portal need separate rules, because a single block can lock out legitimate users. Test from an address outside the list before you rely on it.

Keep admin accounts separate

The security documentation advises against using admin accounts for daily work. Give administrators a second account for configuration tasks and keep sales and service staff on standard roles. Nginx cannot enforce this, but it limits the damage if a daily-use session is hijacked. Review which accounts hold admin rights each quarter and record the owner of each one.

Limit auth token lifetime

Session and authentication token lifetime is set inside EspoCRM, and the documentation recommends keeping it short. A shorter lifetime reduces the window in which a stolen token is useful. Pair it with TLS on every request so tokens never cross the network in clear text. Confirm the chosen values with the users who depend on long sessions, such as field teams on shared devices.

Require two-factor authentication

The documentation recommends requiring 2FA for users. Enable it in EspoCRM for all accounts, and treat it as a separate control from the reverse proxy. If you use OpenID Connect sign-in, note that EspoCRM's own 2FA is not compatible with OIDC, so the identity provider must enforce the second factor instead. Check the chosen approach before rollout, because it changes the login path users see.

Keep UI upgrades disabled

As of version 10.0, upgrading through the UI is disabled by default. Leave that setting in place and run upgrades from the command line under a change record, so the database, files and extensions are backed up first. Anyone who can reach an upgrade screen can change the application, so this default protects the production instance. Check the setting after each upgrade in case a release changes it.

Re-test Nginx after every change

TLS settings, header policy and blocks on internal paths live in the Nginx configuration, not in EspoCRM. After each change, confirm that TLS negotiates correctly, that headers are present, and that requests to internal directories return denial responses. Run the same checks after OS package updates and certificate renewals, because either can alter behavior without a config edit. Record the results with the change.

Nginx differences by Ubuntu environment

A single Ubuntu server with a public hostname is the simplest case. Nginx listens on ports 80 and 443, terminates TLS itself, and passes requests to PHP-FPM. The server block points root at the public directory of the EspoCRM installation, not the application root, so that internal directories are never served directly. Certificates are installed on the host, and the HTTP listener typically exists only to redirect to HTTPS.

  • Server name and certificates: Set server_name to the exact public hostname and point ssl_certificate and ssl_certificate_key at the issued certificate chain.
  • Redirect: Send all port 80 traffic to HTTPS with a permanent redirect, so users never reach an unencrypted login page.
  • Client IP: Nginx sees the real client address, so $remote_addr is correct and IP allowlists in EspoCRM work without extra configuration.
  • Upload and timeout limits: Set client_max_body_size and the FastCGI timeouts on this host directly, since no upstream proxy applies its own limits first.
  • Firewall: Open only 80 and 443 to the internet and keep the database and PHP-FPM socket local.

Before go-live, confirm the DNS record resolves to this server, the certificate covers the hostname, and the ports are reachable from the networks your users actually use.",

Limits to confirm before you copy a server block

A copied Nginx server block is only as good as the environment it lands in. The items below are the checks that decide whether the configuration works on your PHP build, your Ubuntu release, your edge layers and your target EspoCRM version. Confirm each one before you change production.

Exact PHP module list

The module set EspoCRM needs changes between versions, so a list copied from an older guide can leave the application half working. Start from the server configuration docs for your target release, then compare them with the output of php -m on the host. Pay attention to extensions used for database access, image handling, internationalization and the ZMQ extension if real-time updates are planned. Record the list in your build notes so the next upgrade starts from a verified baseline.

PHP version against Ubuntu release

The PHP version you can run depends on the Ubuntu release, its default repositories and whether you add a third-party PHP package source. Check that your release provides a PHP version inside the range EspoCRM documents, and confirm whether PHP-FPM comes from the default archive or a separate repository. Do not assume the distribution default matches the documented range. If it does not, plan the PHP source before you install Nginx.

Upload limits across every layer

Large attachments can fail at several points: client_max_body_size in Nginx, upload_max_filesize and post_max_size in PHP-FPM, and any load balancer, CDN or cloud firewall in front of the host. A value raised in one layer does not raise the others. Test an upload close to your intended limit through the full path, and confirm how your hosting provider handles request body size before you promise users a maximum file size.

WebSocket proxying for real-time features

If you plan to enable real-time notifications, the Nginx block needs an additional location that upgrades the connection and forwards it to the WebSocket daemon. A standard PHP location block will not do this. Confirm whether your edge proxy, load balancer or firewall allows long-lived connections and the Upgrade headers, and check the WebSocket setup guide before you assume real-time updates work.

Release notes for your target version

EspoCRM 10.0.0 was released on July 2, 2026 and 10.0.10 on October 14, 2026, so the version you deploy may carry configuration or requirement changes that older examples do not cover. Read the release notes for the exact version you will install, including any change to upgrade behavior, before you copy a block from a blog or forum. Pin the version in your deployment record.

Questions teams ask before configuring EspoCRM on Nginx

Can our team configure EspoCRM on Nginx without a partner?

Yes, a team with Linux administration experience can do it in-house, and the EspoCRM server configuration docs describe the PHP, database and web server requirements. The work is not large in isolation, but it touches the web server, PHP-FPM, the database, DNS, TLS, file permissions and the cron job that runs background tasks. Teams that already operate Nginx and PHP services usually find the configuration routine. Teams without that experience should weigh the time needed to learn the stack against the cost of getting an exposed CRM wrong.

What skills does an Nginx deployment of EspoCRM require from our staff?

The work needs four skill areas: Linux administration on Ubuntu (packages, services, users, file permissions and logs), PHP-FPM configuration with the extensions EspoCRM requires, database administration for MySQL, MariaDB or PostgreSQL, and DNS and TLS configuration for the public hostname. Someone also needs to read and write Nginx server blocks and understand which directories must be reachable and which must be denied. Confirm the supported PHP and database versions against the EspoCRM server configuration docs before you choose packages.

How long does an Nginx setup take, and what changes the estimate?

Duration depends mostly on what already exists. A host with Nginx, PHP-FPM and a database in place needs a configuration and verification pass, while a new server requires base operating system hardening, package installation and certificate setup first. Other factors include whether you run a single instance or several, whether DNS and certificates are ready, and how much time your team needs for testing uploads, timeouts and access rules. Ask any partner to break the schedule into those phases in the written scope.

What drives the cost of configuring EspoCRM on Nginx?

Cost follows the number of environments (production, staging and recovery), the TLS approach, the number of integrations that need network paths, and the amount of testing you require. Each environment repeats configuration and verification work. A custom certificate chain or a customer portal on its own domain adds DNS and server blocks. Recurring costs are separate: patching the operating system, PHP and EspoCRM, renewing certificates and monitoring logs. When you request a quote, ask for each environment, each domain and each verification step listed separately.

Does the open-source edition of EspoCRM require a license fee?

No license fee applies to self-hosting the open-source edition. The EspoCRM pricing page states that the open-source edition can be downloaded and self-hosted for free, and the espocrm/espocrm repository is licensed under AGPL-3.0. Your costs are infrastructure, labor, and any official extensions or cloud subscriptions you choose. Review the AGPL-3.0 obligations with your legal team if you plan to modify the source and make it available to users over a network.

Is the Ubuntu installation script a faster alternative to a manual Nginx setup?

It can be, for a standard single-server install. EspoCRM provides an installation script for Ubuntu, Debian and Linux Mint that deploys a Docker-based stack with Nginx and MariaDB, optional Let's Encrypt certificates, and a command.sh utility for backups, restores and upgrades. The trade-off is that the script fixes the layout, so you inherit its choices for the web server, database and container setup. If your standards require a host-native Nginx and PHP-FPM stack, plan a manual configuration. Confirm the script's current behavior in the installation docs before you decide.

What should we ask a partner to include in a written Nginx scope?

Ask for a list of systems in scope, including the server OS version, PHP and database versions, and each hostname. Request the server block design for the public directory, client paths, upload size, timeouts and denied internal directories, along with the TLS approach and certificate renewal method. Require a test plan covering login, file uploads, scheduled jobs and access attempts to internal paths. Also ask for handover documentation, a rollback step, the responsibilities of each party after go-live, and the change process for future EspoCRM upgrades.

How DeployOpen approaches EspoCRM Nginx work

DeployOpen starts an Nginx engagement by confirming the target EspoCRM version and the PHP range it supports, because the server block and PHP-FPM setup depend on both. The official server configuration documentation lists PHP 8.3 to 8.5 for current releases, so the first task is matching the installed PHP build against the EspoCRM release you intend to run, and confirming which database (MySQL 8.0 or newer, MariaDB 10.6 or newer, or PostgreSQL 15) sits behind it. Confirm the exact versions with your own change records and with the vendor documentation before the work is scoped, since the supported matrix changes between releases.

Next, the server block is reviewed against your network and security policy rather than copied from a sample. That review covers which paths are served to the browser, how the public directory is separated from the client files, whether the cron-driven background jobs run on the same host, and which internal directories must return a denial. Testing then covers the things that fail quietly in production: the upload size limit, proxy and PHP timeouts for large imports and mass actions, and requests to protected paths that should return a refusal. Each check is run against your staging instance and recorded as evidence.

Most engagements are fixed-scope, with the deliverables, the environments covered and the handover items agreed in writing before work starts. The handover includes a runbook covering the final configuration, the test results, the change procedure for future edits and the steps to roll back a bad reload. Ongoing support, upgrade assistance and periodic configuration reviews are available as a retainer, which suits teams that expect to change EspoCRM versions or hosting limits over time.

How DeployOpen delivers EspoCRM hosting work

DeployOpen plans, implements, hardens, documents and supports self-hosted open-source platforms inside your own infrastructure, including your cloud accounts, data centers or air-gapped networks. For EspoCRM Nginx configuration on Ubuntu, that means the web server, PHP-FPM runtime and access rules are agreed in writing, built in your environment and handed over with the evidence your team needs to run them.

How we scope

  • We confirm the Ubuntu release, Nginx and PHP-FPM versions, and the EspoCRM release you plan to run before any configuration is written.
  • The written scope lists the server block, PHP modules, upload and timeout settings, and the internal directories that must be denied.
  • We agree which hostnames, TLS approach and access sources apply, so the scope matches your network and certificate process.

How we build

  • We build the Nginx server block with the public directory as the document root and test that internal paths return denial responses.
  • We configure PHP-FPM with the modules EspoCRM requires and set upload size and timeouts to values agreed in the scope.
  • We test uploads, long-running requests, the cron schedule for background jobs and login behavior before handing the system over.

How we hand over

  • You receive the final Nginx and PHP-FPM configuration files, with a record of every change made from the EspoCRM defaults.
  • The documentation explains how to reload the configuration safely, check logs, and verify denied paths after an update.
  • Your team gets a test checklist covering uploads, TLS, internal directory access and scheduled jobs to repeat after changes.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer, scoped separately from the initial build.
  • When you move to a new EspoCRM release or PHP version, we review the server configuration against the release notes before the change.
  • Retainer work can include re-running the access and denial tests after host changes, so configuration drift is caught early.

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.