Ubuntu 18.04 Server: install and configure Nginx, PHP, and MariaDB

To use Nginx, PHP-FPM, and MariaDB together on Ubuntu 18.04, you need to install each package, pass Nginx's PHP requests to the PHP-FPM socket, and then set up the database with separate accounts. The example below is a local-only practice that does not change existing sites, and it does not use the database root account for web applications.

Scope of Practice and Preparation

General security support for Ubuntu 18.04 has ended. Check whether Ubuntu Pro's Extended Security Maintenance (ESM) is applied and the support range for each package at Ubuntu Security Maintenance Schedule, and it is recommended to build new operating environments with supported versions. This article uses PHP 7.2 from the default repository as an example to understand an existing 18.04 server.

Prepare a separate test server with administrator privileges and repository access. Nginx handles web requests, PHP-FPM (FastCGI Process Manager) executes PHP code, and MariaDB stores data. Examples are received only in 127.0.0.1:8080, so you cannot access them directly from outside the server. For public internet access, separate firewall, domain, TLS certificate, and security review are required.

On servers with existing services or data, prepare backup and recovery procedures before making changes. If the practice paths, accounts, database names, or port 8080 below are already in use, do not proceed as is; use a separate test environment. You can check port usage with the following command. If there is no output, there is no TCP listener for that port.

sudo ss -lntp | grep ':8080 '

Package installation and service verification

Installing the packages can automatically start the default Nginx site listening on port 80. Restricting the demo site to local port 8080 does not restrict that default site. Isolate the test server with network and firewall controls before installing, and check the impact on existing services.

After updating the package list, install Nginx, PHP 7.2 FPM with MySQL driver, MariaDB server, and curl for verification. If packages cannot be used due to repository or support issues, resolve the errors before proceeding.

sudo apt update
sudo apt install nginx php7.2-fpm php7.2-mysql mariadb-server curl

After installation, check the service status and PHP-FPM socket using the following commands. If the service is not running, identify the cause and start the service. If the socket path is different, adjust the Nginx configuration below to match the actual path.

systemctl is-active nginx php7.2-fpm mariadb
ls -l /run/php/

Check whether each of the three services is active. If php7.2-fpm.sock does not exist, check the cause in systemctl status php7.2-fpm and the service logs. When the PHP version is different, you must change both the package and the socket path together.

Nginx and PHP-FPM connection

Create a new practice directory and configuration file. Do not overwrite /var/www/lnmp-demo, /etc/nginx/sites-available/lnmp-demo, or /etc/nginx/sites-enabled/lnmp-demo if they already exist. Execute the editing commands below after confirming there is no existing path on a clean server.

sudo mkdir /var/www/lnmp-demo
sudo nano /etc/nginx/sites-available/lnmp-demo

Save the following full server block in the editor. fastcgi_pass must match the PHP-FPM socket confirmed earlier. snippets/fastcgi-php.conf is a configuration snippet from the Ubuntu Nginx package; if the file does not exist, check the FastCGI settings in the distribution.

server {
    listen 127.0.0.1:8080;
    server_name localhost;
    root /var/www/lnmp-demo;
    index index.php;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
    }
}

Activate and check the configuration file. Only reload if nginx -t succeeds. If it fails, check and correct errors, ports, and socket paths, then recheck. If a problem occurs, remove only the symbolic links created in this practice, then recheck and reload to maintain the existing site configuration.

sudo ln -s /etc/nginx/sites-available/lnmp-demo /etc/nginx/sites-enabled/lnmp-demo
sudo nginx -t
sudo systemctl reload nginx

Nginx FastCGI connections can also be checked in Nginx Official Guide.

Check PHP Execution

Check that there is no file in the path below and create a new file. Save the code below in your editor.

sudo nano /var/www/lnmp-demo/index.php
<?php
header('Content-Type: text/plain; charset=UTF-8');
echo "PHP is working\n";
echo 'SAPI: ' . PHP_SAPI . "\n";

Run the following command on the same server. If PHP is working and SAPI: fpm-fcgi appear, Nginx has executed the code through PHP-FPM. If the PHP code is displayed as-is, the configuration has not been applied, so do not expose the test file and check the FastCGI settings again.

curl http://127.0.0.1:8080/

If there is a 502 error, check the PHP-FPM service, socket path, and permissions; if there is a 404 error, check the document directory and file path. Do not expose the phpinfo() page that discloses detailed server settings.

MariaDB Database and Separate Account

MariaDB administrator authentication depends on the installation method. If local socket authentication is set, you can open the management console with the following command. If it fails, verify the existing administrator authentication method. MYSQL_HISTFILE=/dev/null specifies that this client session should not leave a command history file.

sudo env MYSQL_HISTFILE=/dev/null mysql

The following is SQL to create a new practice database and a local-only account. If the same name already exists, do not modify the existing entry; use a different name. Before execution, replace CHANGE_ME_STRONG_PASSWORD with a long, unique password, and ensure that any quotes or backslashes in the SQL string are properly escaped.

CREATE DATABASE lnmp_demo CHARACTER SET utf8mb4;
CREATE USER 'lnmp_demo'@'localhost' IDENTIFIED BY 'CHANGE_ME_STRONG_PASSWORD';
GRANT SELECT ON lnmp_demo.* TO 'lnmp_demo'@'localhost';
EXIT;

This example account has read-only permissions on the database. If an actual application requires write or schema-changing permissions, grant only the necessary permissions separately. Do not directly modify the authentication plugin of the admin account or give root privileges to the web application. For more details on accounts and authentication, refer to MariaDB CREATE USER documentation.

Verify that the new account can connect locally. Do not write the password directly on the command line; enter it at the prompt. After connecting, executing SELECT DATABASE(), CURRENT_USER(); will display the database and authenticated accounts. Exit the console using EXIT;.

mysql -u lnmp_demo -p lnmp_demo

Check database connection in PHP

The following is a temporary verification method using the account created above. Keep credentials outside of the web document directory. If /etc/lnmp-demo already exists, do not overwrite it; use a separate test environment instead. This assumes the default configuration where PHP-FPM runs under the www-data group.

sudo install -d -m 750 -o root -g www-data /etc/lnmp-demo
sudo install -m 640 -o root -g www-data /dev/null /etc/lnmp-demo/db.php
sudo nano /etc/lnmp-demo/db.php

Insert the following content into the file, and replace the password with the value set for the database account. If there are quotes or backslashes in the PHP string, escape them correctly. Since other applications running with the same www-data permissions can also read the file, separate isolation is required on shared servers.

<?php
return array(
    'user' => 'lnmp_demo',
    'password' => 'CHANGE_ME_STRONG_PASSWORD',
);

Ensure /var/www/lnmp-demo/db-check.php does not exist and save the following code. Only indicate the success or failure to avoid exposing error messages or passwords in the web response.

sudo nano /var/www/lnmp-demo/db-check.php
<?php
header('Content-Type: text/plain; charset=UTF-8');
ini_set('display_errors', '0');
$config = require '/etc/lnmp-demo/db.php';
try {
    $db = new PDO('mysql:host=localhost;dbname=lnmp_demo;charset=utf8mb4',
        $config['user'], $config['password'],
        array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
    echo "Database connection OK\n";
} catch (PDOException $e) {
    http_response_code(500);
    echo "Database connection failed\n";
}
curl -i http://127.0.0.1:8080/db-check.php

If HTTP 200 and Database connection OK appear, the PHP connection to MariaDB has succeeded. If it fails, check the PHP MySQL extension, service status, socket authentication, and account/password. After verification, safely remove temporary PHP files and credential files, and clean up the practice accounts and databases that are no longer needed, checking both the actual targets and backups.

Before applying to the production environment

The practice setup is for local connection verification. Before making actual services public, migrate to supported OS and PHP versions, and configure the Nginx server name and document root, HTTPS certificates, firewall, and cloud network rules according to the environment. You also need to review PHP file upload/execution scope, FPM user separation, and MariaDB network access, backup, and recovery.

The MariaDB security configuration tool is provided as mysql_secure_installation or mariadb-secure-installation depending on the installed version. Since it may affect existing services, read each question and choose according to your environment. Detailed items can be found in Description of the MariaDB Security Configuration Tool.