Deploying PHP Apps (Nginx + PHP-FPM)
"Deploying a PHP App (Nginx + PHP-FPM)" refers to the steps required to run a PHP application in production on an Ubuntu server. You install and configure PHP-FPM, set up an Nginx virtual host, apply appropriate file permissions, and start the services. Executing each step in the correct order lets you build a secure and stable PHP runtime environment.
Syntax
# -----------------------------------------------
# PHP App Deployment Overview (Ubuntu / Nginx + PHP-FPM)
# -----------------------------------------------
# Step 1: Install PHP-FPM
# -----------------------------------------------
# apt install php{version}-fpm
# → Installs PHP-FPM (FastCGI Process Manager)
# → Because Nginx cannot execute PHP directly,
# it delegates processing to PHP-FPM via FastCGI
# Example: sudo apt install php8.3-fpm
# -----------------------------------------------
# Step 2: Configure the Nginx Virtual Host
# -----------------------------------------------
# /etc/nginx/sites-available/{site-name}
# → Creates the virtual host configuration file
# Example: sudo nano /etc/nginx/sites-available/dragonball-app
# ln -s /etc/nginx/sites-available/{site-name} /etc/nginx/sites-enabled/
# → Enables the configuration via a symbolic link
# Example: sudo ln -s /etc/nginx/sites-available/dragonball-app \
# /etc/nginx/sites-enabled/dragonball-app
# nginx -t
# → Checks the configuration file for syntax errors
# → Always run this before deploying
# -----------------------------------------------
# Step 3: Set File Permissions
# -----------------------------------------------
# chown -R {user}:{group} {app-directory}
# → Sets the owner of the application files
# → Grants ownership to the user that PHP-FPM runs as
# Example: sudo chown -R www-data:www-data /var/www/dragonball-app
# chmod -R 755 {directory}
# → Sets access permissions on directories
# → Owner: read/write/execute / Group & others: read/execute
# chmod -R 644 {file}
# → Sets access permissions on files
# → Owner: read/write / Group & others: read-only
# -----------------------------------------------
# Step 4: Start and Enable Services
# -----------------------------------------------
# systemctl start php{version}-fpm
# → Starts PHP-FPM
# Example: sudo systemctl start php8.3-fpm
# systemctl enable php{version}-fpm
# → Registers PHP-FPM to start automatically on server reboot
# systemctl reload nginx
# → Reloads the Nginx configuration without restarting
# → Applies the new configuration while keeping existing connections alive
Command Reference
| Step | Description |
|---|---|
| Install PHP-FPM | Run sudo apt install php8.3-fpm to install PHP-FPM. This is required for Nginx to execute PHP. Installing extension modules such as php8.3-mbstring at the same time is convenient. |
| Verify PHP-FPM is running | Run systemctl status php8.3-fpm to check that the process is working correctly. If it shows active (running), the service is up. |
| Create the virtual host configuration file | Create a configuration file under /etc/nginx/sites-available/. Specify the PHP-FPM socket with fastcgi_pass unix:/run/php/php8.3-fpm.sock;. |
| Enable the configuration | Create a symbolic link with ln -s /etc/nginx/sites-available/{site-name} /etc/nginx/sites-enabled/ to activate the configuration. |
| Check Nginx configuration syntax | Run sudo nginx -t to validate the configuration file syntax. If it shows syntax is ok, there are no issues. Always run this before applying changes. |
| Set the owner | Run sudo chown -R www-data:www-data {directory} to set the file owner to www-data, the user that Nginx and PHP-FPM run as. |
| Set directory permissions | Run sudo chmod -R 755 {directory} to set directories to "owner: read/write/execute / others: read/execute". |
| Set file permissions | Run sudo chmod -R 644 {file} to set files to "owner: read/write / others: read-only". This protects PHP files from being modified by other users. |
| Reload Nginx configuration | Run sudo systemctl reload nginx to apply the configuration without dropping existing connections. This is safer than restart and is suitable for updating configuration in production. |
| Enable auto-start | Run sudo systemctl enable php8.3-fpm nginx to register both services to start automatically after a server reboot. |
Examples
PHP App Deployment Steps (Ubuntu / Nginx + PHP-FPM)
# ===============================================================
# Deployment steps for dragonball-app
# Environment: Ubuntu 22.04 / Nginx / PHP 8.3-FPM
# ===============================================================
# -----------------------------------------------
# 1. Update packages and install PHP-FPM
# -----------------------------------------------
# Update the package list
sudo apt update
# Install PHP 8.3 FPM and required extension modules
# mbstring: multibyte string processing (e.g., Japanese)
# xml: XML parsing (required by some frameworks)
# curl: HTTP requests to external APIs
# mysql: connection to MySQL / MariaDB databases
sudo apt install php8.3-fpm php8.3-mbstring php8.3-xml php8.3-curl php8.3-mysql
# Install Nginx if it is not already installed
sudo apt install nginx
# -----------------------------------------------
# 2. Deploy the application files
# -----------------------------------------------
# Create the application root directory
sudo mkdir -p /var/www/dragonball-app/public
# Transfer the application files to the server
# (Example: uploading from local machine via rsync)
# rsync -avz ./src/ user@your-server:/var/www/dragonball-app/
# -----------------------------------------------
# 3. Set file permissions
# -----------------------------------------------
# Change the owner of the entire app to www-data (the user Nginx / PHP-FPM runs as)
sudo chown -R www-data:www-data /var/www/dragonball-app
# Set directories to 755 (owner: rwx / group & others: r-x)
# Execute permission is required to traverse (enter) a directory
sudo find /var/www/dragonball-app -type d -exec chmod 755 {} \;
# Set regular files such as PHP files to 644 (owner: rw- / others: r--)
# This prevents other users from modifying the files
sudo find /var/www/dragonball-app -type f -exec chmod 644 {} \;
# Set the upload directory to 775 so PHP-FPM can write to it
# (Only if an uploads directory exists)
sudo chmod -R 775 /var/www/dragonball-app/public/uploads
# -----------------------------------------------
# 4. Configure the Nginx virtual host
# -----------------------------------------------
# Create the virtual host configuration file
sudo tee /etc/nginx/sites-available/dragonball-app <<'EOF'
server {
listen 80;
server_name dragonball-app.example.com;
# Set the document root to the public directory
root /var/www/dragonball-app/public;
index index.php index.html;
# Handle regular requests
# Falls back to index.php if the file does not exist
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Forward PHP files to PHP-FPM
location ~ \.php$ {
# Only process files that actually exist
# to prevent directory traversal attacks
try_files $uri =404;
# Load basic FastCGI parameters
include fastcgi_params;
# Specify the PHP-FPM socket file
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
# Set the script name for the entry point
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Deny access to hidden files such as .htaccess
location ~ /\. {
deny all;
}
}
EOF
# Create a symbolic link from sites-available to sites-enabled to activate the config
sudo ln -s /etc/nginx/sites-available/dragonball-app \
/etc/nginx/sites-enabled/dragonball-app
# -----------------------------------------------
# 5. Verify configuration and start services
# -----------------------------------------------
# Check the Nginx configuration file for syntax errors
# Fix any errors before running reload
sudo nginx -t
# Start PHP-FPM and register it to start automatically on reboot
sudo systemctl start php8.3-fpm
sudo systemctl enable php8.3-fpm
# Reload the Nginx configuration (applies changes while keeping connections alive)
sudo systemctl reload nginx
# Register Nginx to start automatically on server reboot as well
sudo systemctl enable nginx
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl status php8.3-fpm
● php8.3-fpm.service - The PHP 8.3 FastCGI Process Manager
Loaded: loaded (/lib/systemd/system/php8.3-fpm.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2026-03-25 10:00:00 JST; 3s ago
Main PID: 12345 (php-fpm8.3)
Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
$ sudo systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2026-03-25 10:00:05 JST; 2s ago
$ ls -la /var/www/dragonball-app/public/
total 20
drwxr-xr-x 2 www-data www-data 4096 Mar 25 10:00 .
drwxr-xr-x 3 www-data www-data 4096 Mar 25 10:00 ..
-rw-r--r-- 1 www-data www-data 312 Mar 25 10:00 index.php
-rw-r--r-- 1 www-data www-data 128 Mar 25 10:00 goku.php
-rw-r--r-- 1 www-data www-data 128 Mar 25 10:00 vegeta.php
Overview
"Deploying a PHP App (Nginx + PHP-FPM)" is based on the fact that Nginx cannot execute PHP directly. When Nginx receives a request, it forwards it to PHP-FPM via the UNIX socket specified in the fastcgi_pass directive, and PHP-FPM executes the PHP script and returns the result. In the Nginx virtual host configuration, it is common practice to use try_files $uri $uri/ /index.php?$query_string; to implement URL routing. File permissions should be configured based on www-data, the user that PHP-FPM runs as: regular files at 644, directories at 755, and only upload directories that need write access at 775, which maintains security. In production environments, firewall configuration is also important — use ufw to allow only HTTP (port 80) and HTTPS (port 443).
If you find any errors or copyright issues, please contact us.