LEMP Field Notes
Stack Guides

LEMP Stack Production Setup: Pre-Deploy Checklist

LEMP Stack Production Setup: Pre-Deploy Checklist
In briefA production-ready LEMP stack needs more than running services. Before deployment, verify a recoverable backup, restricted network exposure, active security updates, explicit Nginx host routing, valid TLS renewal, production PHP error handling, least-privilege database access, durable logs, monitoring, and a tested rollback. Record installed versions and effective configuration instead of trusting a tutorial's defaults. This checklist gives each gate an owner and evidence; it deliberately contains no untested commands.

What makes a LEMP stack ready for production?

A production-ready LEMP stack is a system you can inventory, restrict, observe, recover, and roll back. Running Nginx, PHP-FPM, and MySQL or MariaDB proves only that the components start. Before real traffic arrives, require evidence for recovery, network exposure, updates, host routing, TLS renewal, PHP behavior, database access, logging, monitoring, and rollback.

This checklist deliberately contains no shell commands. No Ubuntu 24.04 test host was available for testing commands as written, so publishing copy-and-paste steps would be guesswork. The linked implementation guides carry the procedures; this page defines the production gates those procedures must satisfy.

Gate Evidence to keep Failure it prevents
Inventory OS release, package origins, installed versions, active configuration Tuning the wrong service or file
Recovery A completed restore rehearsal Discovering that a backup cannot be restored
Exposure Listener and firewall review Publishing an administrative service
Updates Update history and maintenance owner Leaving known fixes unapplied
Nginx Host-routing and configuration-validation results Serving the wrong site or invalid configuration
TLS Renewal test and expiry alert An avoidable certificate outage
PHP-FPM Pool, error, queue, and capacity evidence Data disclosure or worker exhaustion
Database Account, privilege, listener, and restore review Excessive access or unrecoverable data
Deployment Release identifier and rollback rehearsal A one-way release
Monitoring External checks and routed alerts A quiet failure

Start with the effective system, not remembered defaults

Record the operating-system release, installed package versions, package sources, enabled services, and listening network sockets. Then record the effective Nginx configuration, the PHP-FPM pools and configuration inputs, and the exact database product and edition. “LEMP” does not identify those facts.

Do not infer a PHP socket name, service name, configuration path, process-manager mode, database bind address, or package version from a tutorial. Nginx itself documents several possible configuration locations because installation methods differ. MySQL documents how to inspect the values used by the running server. The relevant evidence is what this server loaded, not what a sample file contains.

If the machine is not installed yet, the Ubuntu 24.04 LEMP installation guide covers the installation sequence. Return here after installation and inventory the resulting system.

Prove recovery before changing production settings

A backup job reporting success is not recovery evidence. Define what must be recoverable: application data, database contents, uploaded files, configuration, secrets, and any metadata needed to resume service.

Run a restoration rehearsal into an isolated target that cannot overwrite production. Confirm the application can read the restored data, not merely that an archive can be opened. Record the restore duration you actually observed instead of promising a recovery time you have not measured.

MySQL’s security documentation explicitly calls for an appropriate recovery solution and a test that information can be recovered from backups. Choose the documented procedure for the installed database product and version. Do not assume a procedure for one engine applies to another.

Reduce exposure at every network boundary

Compare listening sockets with both the provider firewall and the host firewall. Every reachable listener needs a reason, an owner, and an approved source range. Ubuntu documents UFW as initially disabled; verify the machine’s current state.

Protect administrative access before changing firewall or SSH policy. Keep a tested second session or provider-console path so a mistaken rule does not cause a lockout. This gate is complete only when observed reachability matches the approved design.

PHP’s manual gives a sharper boundary: PHP-FPM must not be reachable from an untrusted network because a FastCGI client can influence request configuration. Limit the FPM endpoint to the intended local or private caller. Apply the same test to the database. Public database access is not a harmless default to tidy later.

Make security updates an operation, not an intention

Check that the Ubuntu release is still in the support window relevant to its enabled repositories. Review recent update activity, pending updates, failed jobs, and whether a reboot is waiting. Assign an owner and a maintenance path for updates that require service restarts or a host reboot.

Ubuntu says unattended-upgrades is included in default Server installations from Ubuntu 18.04 LTS and applies security updates automatically. It also says third-party repositories and PPAs are not covered automatically unless configured. Those are documented installation behaviors, not proof about this machine. Inspect the effective policy and its logs.

Ubuntu also documents AppArmor as installed and loaded by default. Confirm its current status and investigate denials rather than disabling enforcement to make an unexplained failure disappear.

Prove Nginx routes only the intended hosts

Nginx selects a virtual server by listening address and port, then by the request’s Host field. If no name matches, the default server for that address and port handles the request. Test every expected hostname and an unexpected hostname over every exposed address family. An unmatched request must not reveal another application, a setup page, or a directory intended for a different site.

Confirm each document root contains only public assets and the application’s public entry point. Keep diagnostic pages, environment files, database dumps, deployment archives, and private keys outside it.

Before any reload, validate the complete effective configuration. Nginx’s test checks syntax and attempts to open referenced files. A failed reload keeps the old configuration, but that does not protect against a syntactically valid mistake. Preserve the previous reviewed configuration and define a rollback trigger.

Use the Nginx server-block guide for implementation details. Production sign-off needs the routing results, not a screenshot of a configuration file.

Treat TLS renewal as part of the service

Confirm HTTPS serves the expected certificate for every production hostname and that the intended redirect works. Verify the renewal mechanism installed on this host; Certbot says the installation method determines the actual setup.

Run a renewal dry run through the approved, tested procedure and route renewal failure and certificate-expiry alerts to a monitored destination. Record who responds. Do not manually edit Certbot renewal files; its documentation warns that this can break renewal. The Nginx and Certbot guide covers certificate implementation.

Size PHP-FPM from measurements

Identify each application’s pool, operating-system identity, and Nginx endpoint. Separate pools where applications cross a trust boundary. Limit write access to required directories.

PHP-FPM supports static, dynamic, and on-demand process management. Capacity is not a universal number. Measure worker memory, concurrency, and queue behavior; leave headroom for Nginx, the database, the operating system, and bursts; then set a sustainable limit. Recheck after application or extension changes.

PHP states that displayed errors should be disabled in production because output can reveal confidential information, while error logging can preserve diagnostic detail. Verify both the browser response and the log destination. If the FPM status page is enabled, PHP says it must be limited to internal requests or known client addresses because it reveals request URLs and resource information.

Verify OPcache behavior against the deployment method. PHP documents that disabling timestamp validation requires an explicit cache reset or web-server restart before filesystem changes take effect. Do not copy cache sizes or validation settings from another host. Confirm that a release becomes visible when expected and that rollback does too.

Finally, align request and upload limits across Nginx, PHP, and the application. The smallest effective limit wins, and inconsistent settings produce failures that look intermittent to users.

Give the application the smallest database role it needs

Use a dedicated application account rather than an administrative account. MySQL’s privilege guidance says an account should receive only the privileges it needs and calls for particular caution with file and administrative privileges. Review privileges against real application operations, including migrations, instead of granting broad access to avoid a deployment error.

Check both account host scope and the database listener. MySQL documents that bind addresses determine which interfaces accept connections; MariaDB behavior and packaged configuration can differ. If the database is local, prove it is not reachable from an untrusted network. If it is remote, restrict the route and use the installed product’s documented transport protection.

Store credentials outside the public document root, restrict who can read them, and document rotation. Monitor authentication failure, connection exhaustion, storage pressure, and slow queries without exposing query text or secrets.

Make the deployment reversible

Give every release an immutable identifier. Record the artifact, configuration revision, migration state, validation result, and rollback decision. File timestamps are not a release record.

Define which changes can roll back independently and which database changes require a forward fix. Test the rollback path before traffic depends on it. Account for scheduled tasks, background workers, caches, and writable data that a web-only check misses.

Keep ownership and permissions explicit, but do not copy a universal numeric mode. The correct access depends on which identities deploy, serve, and write. The evidence is that each identity can do exactly its job and cannot modify unrelated code, configuration, or secrets.

Monitor the entire request path

An external HTTPS check proves more than a local process check: DNS, routing, Nginx, TLS, and at least one response path must all work. Add application checks that exercise PHP and, where safe, a database read. Keep the health endpoint cheap and prevent it from disclosing versions, configuration, or credentials.

Monitor HTTP error rate, request time, Nginx errors, PHP-FPM queue and capacity signals, database connection pressure, disk space and inodes, memory pressure, backup results, and certificate renewal. Thresholds must come from measured baseline and service requirements, not a generic checklist.

Route every actionable alert to a person or rotation. Record the first diagnostic link and the escalation path. An alert without an owner is a log entry with better typography.

Run one launch rehearsal

Before DNS or traffic changes, rehearse the production path using the real hostname and intended address families. Verify HTTP and HTTPS behavior, static files, a PHP request, a database-backed request, expected not-found and error responses, logging, and any application feature that writes data or schedules work.

Then test service recovery after the kind of restart your maintenance plan permits. Confirm monitoring notices the interruption and recovery. Finish by reviewing the rollback trigger and the evidence table with the person responsible for the launch.

Mark a gate complete only when its evidence exists. “Configured” describes an action. “Observed working, recoverable, and monitored” describes a production system.

Sources

An independent publication. Not affiliated with any prior owner of this domain.

FAQ

What should I change before putting a LEMP stack into production?

Start by inventorying the effective configuration, then verify recovery, network exposure, security updates, Nginx host routing, TLS renewal, PHP error handling, database privileges, logs, monitoring, and rollback. Do not copy process counts, timeouts, cache sizes, or listener settings from another server. Measure the workload and keep evidence for every completed gate.

Is an installed LEMP stack ready for production?

No. Successful installation proves that Linux, Nginx, PHP-FPM, and the database can start and communicate. Production readiness also requires restricted access, recoverable backups, validated routing, renewable TLS, safe error handling, least-privilege accounts, monitoring, and a reversible deployment. Each item needs an observed result rather than an assumption about package defaults.

How do I choose PHP-FPM worker limits?

Measure worker memory under representative requests and observe concurrency and queue behavior. Reserve capacity for Nginx, the database, the operating system, and traffic bursts, then choose a limit the host can sustain. Recheck after changes to the application or PHP extensions. A worker count copied from a different machine is not evidence.

Should MySQL or MariaDB be reachable from the internet?

Not unless the architecture explicitly requires remote database access. For a database used only by applications on the same host, verify that its listener is unavailable to untrusted networks. For a remote database, restrict network routes and account host scope, use the installed product's documented transport protection, and grant the application only the privileges it needs.

How do I know a LEMP backup is usable?

Restore it into an isolated target and prove that the application can read the recovered data. Include the database, uploaded files, configuration, secrets, and any metadata needed to resume service. Record the observed restoration time, the responsible owner, and the product-version requirements. A successful backup job alone does not prove recoverability.

What should a LEMP production monitor check?

Use an external HTTPS check for DNS, routing, Nginx, and TLS, then add safe checks for PHP and a database read. Monitor HTTP errors and latency, Nginx logs, PHP-FPM queue and capacity, database connections, disk space and inodes, memory pressure, backup results, and certificate renewal. Every actionable alert needs a monitored destination and an owner.