Run PHP-FPM with nginx on Ubuntu, Not Apache
Put nginx in front of PHP-FPM on Ubuntu 24.04 so static files, TLS, and PHP workers stay isolated, then ship a unix-socket vhost ready for production traffic.
Netbay Engineering
Netbay Engineering
On this page
Apache with mod_php is still the default mental model for a lot of PHP hosting, but it is the wrong default on a VPS in 2026. nginx plus PHP-FPM separates the HTTP worker from the PHP worker. That split is the entire production story: nginx handles keep-alives, static files, TLS, and buffering, while PHP-FPM owns process limits, pools, and the interpreter. On a 2 GB Ubuntu box the difference is not theoretical. Apache with prefork and mod_php pins a full interpreter in every HTTP child; idle keep-alives waste RAM that should have gone to opcache.
This walkthrough installs nginx and PHP 8.3 FPM on Ubuntu 24.04, wires a unix socket, and serves a real app root. The same layout works for Laravel, WordPress, and a plain public/index.php. You will not install Apache. If a tutorial still starts with apt install apache2 libapache2-mod-php, close it and use the stack below instead.
Why nginx plus FPM, not Apache
Apache is not bad software. It is the wrong process model for PHP on a small VPS. mod_php embeds the interpreter inside the HTTP server. Every spare Apache child then holds Zend, extensions, and a memory map that fights opcache. Prefork is the historically safe MPM for that embedding, and prefork is RAM-heavy.
PHP-FPM (FastCGI Process Manager) runs PHP as its own daemon. nginx never loads PHP. It proxies .php requests over a unix socket to a pool of php-fpm workers. Static assets never touch PHP at all. That is the whole win: nginx can keep hundreds of idle TLS connections cheaply, and PHP only consumes RAM when a request actually needs the interpreter.
On Intel Xeon Platinum VPS plans the CPU is rarely the bottleneck for typical PHP apps. Memory is. Isolating PHP workers lets you size pm.max_children against real RAM instead of against Apache KeepAliveTimeout. A second reason is operational. nginx config is a handful of directives. TLS, gzip, and FastCGI buffering live in one file. You can reason about request flow without Apache nested modules.
Event MPM plus php-fpm via FastCGI is a valid Apache setup, but it is not simpler than nginx, and Ubuntu LAMP meta-packages still drag you toward mod_php. Start with nginx. You can always add Apache later if a legacy .htaccess dependency forces it, which it almost never should on a VPS you control.
Install nginx and PHP-FPM on Ubuntu 24.04
Start from a clean Ubuntu 24.04 image in Lucknow. Update packages, then install nginx and the FPM stack. Pull the common extensions most apps expect: mysql or pgsql, xml, mbstring, curl, zip, intl, and gd.
sudo apt-get update
sudo apt-get install -y nginx php8.3-fpm php8.3-cli php8.3-mysql php8.3-xml php8.3-mbstring php8.3-curl php8.3-zip php8.3-intl php8.3-gd
sudo systemctl enable --now nginx php8.3-fpm
sudo systemctl status php8.3-fpm --no-pager
ls -l /run/php/php8.3-fpm.sockUbuntu 24.04 ships PHP 8.3 in the default repos. That is new enough for Laravel 11 and current WordPress. Do not add a third-party PHP PPA unless you have a version pin you can defend for the life of the box. Confirm both daemons are active and that the socket exists under /run/php/. That path is the contract nginx will use. Never expose FPM on a TCP port bound to 0.0.0.0.
The php8.3-fpm unit is a systemd service with its own logs in /var/log/php8.3-fpm.log and a pool file at /etc/php/8.3/fpm/pool.d/www.conf. Leave the default pool on the unix socket. Process counts come later; a fresh install is already enough to prove the request path.
A production vhost, socket not TCP
Put the application at /var/www/app with the web root at /var/www/app/public. Laravel and Symfony already use public/. For WordPress the web root is the install directory itself; adjust the root directive accordingly. Disable the default site, then drop a vhost that only talks to FPM over the socket.
server {
listen 80;
listen [::]:80;
server_name app.example.com;
root /var/www/app/public;
index index.php;
client_max_body_size 32m;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ .php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_hide_header X-Powered-By;
}
location ~ /. {
deny all;
}
}try_files is the important line. nginx serves the file if it exists; otherwise it internally rewrites to index.php. That is how Laravel routing and WordPress permalinks work without Apache rewrite soup. SCRIPT_FILENAME must point at the real PHP file. Ubuntu snippets/fastcgi-php.conf already sets this for most sites. If you write the location by hand, set it explicitly or you will debug blank pages for an hour.
Reload nginx with nginx -t && systemctl reload nginx. Drop a phpinfo file in public/ only long enough to confirm FPM is answering, then delete it. phpinfo in production is a gift to scanners. Enable HTTPS next with certbot or a Caddy sibling; this post stays on the PHP request path.
Permissions and the socket
The nginx worker user is www-data. The FPM pool user should also be www-data, or a dedicated app user whose group nginx can traverse. The unix socket must be readable by nginx. Ubuntu php8.3-fpm already sets listen.owner and listen.group to www-data in www.conf. Leave that alone unless you have a reason.
Application files should be owned by a deploy user, not by root, with group www-data and directories at 750/640 except for storage paths that must be writable. Get a request from nginx to FPM to index.php and back before you chase queue workers or opcache knobs.
What you should not install
Skip libapache2-mod-php. Skip php-cgi. Skip a TCP listen on 127.0.0.1:9000 unless FPM lives in a separate namespace and a firewall makes that bind safe. A unix socket is faster and cannot be reached from another machine if you misconfigure a listen address.
Skip a full LAMP meta-package. It pulls Apache, extra modules, and fights nginx for port 80. Install only what the app imports. Skip default server tokens and directory indexes. Add DDoS Protected networking at the VPS edge (L3/L4 filtering) so the PHP layer is not your first defense against floods.
Takeaway
Production PHP on Ubuntu is nginx in front, PHP-FPM behind a unix socket, and a web root that is not the project root. That layout is boring, which is the point. It scales from a 2 GB Lucknow VPS to a larger Xeon Platinum plan without changing the request path.
You can spin up an Ubuntu 24.04 instance on Netbay in under 60 seconds and follow along — netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance