Installing phpMyAdmin on Nginx using a PPA and SSL

October 2, 2015

This article explains how to install phpMyAdmin on your Nginx server using a Ubuntu PPA (Personal Package Archives), and self-signing an SSL certificate for added security. It assumes you are running Nginx and PHP-FPM.

The motivations for using this setup:

  • No need to manually update phpMyAdmin
  • Take advantage of SSL

Install phpMyAdmin

The PPA ppa:vincent-c/ppa holds stable upstream versions of phpMyAdmin and seems to be updated fairly often.

Install the PPA and the phpMyAdmin package:

sudo add-apt-repository ppa:vincent-c/ppa
sudo apt-get update
sudo apt-get install phpmyadmin

Say yes when it asks whether to use dbconfig-common.

Create a PHP-FPM Pool

PHP-FPM creates a master process that that forwards HTTP requests to one or more child processes. A PHP-FPM pool is a collection of related PHP child processes, and it's not uncommon to have one such pool for each PHP application.

We'll create a dedicated PHP-FPM pool and socket for phpMyAdmin. This pool will run as the user pma.

First, create the user:

adduser pma

Then create a new PHP-FPM pool config file file based on the default www.conf:

cd /etc/php5/fpm/pool.d/
sudo cp www.conf pma.conf

Edit pma.conf (I'm only showing the directives I've changed):

[pma]

user = pma
group = pma
listen = /var/run/php5-fpm-pma.sock
pm = ondemand
pm.max_children = 4
pm.process_idle_timeout = 15s;
security.limit_extensions = .php
php_admin_value[error_log] = /var/log/fpm-php.pma.log

Notice the first line: Each pool configuration begins with [pool-name], hence pma is the name of our new pool.

These settings are probably not recommended for your typical PHP website or app; the phpMyAdmin installation will not generate a lot of traffic, so it has been deliberately allocated a small amount of resources (see pm, pm.max_children, pm.process_idle_timeout).

Restart PHP-FPM:

sudo service php-fpm restart

Create and install an SSL certificate

Because the only one accessing phpMyAdmin is myself, and because my only concern is that the traffic is encrypted, I'll use a self-signed certificate.

Create a self-signed SSL certificate:

sudo mkdir /etc/ssl/pma
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/pma/pma.key \
-out /etc/ssl/pma/pma.crt

The question that you must answer correctly is the "Common Name". Use your domain name or Server IP Address for this field. I will use pma.myserver.example.com.

Create a Server Block

The next step is to create an Nginx server block ("Virtual Host") for phpMyAdmin that responds to pma.myserver.example.com.

Create /etc/nginx/sites-available/phpmyadmin.conf:

# Redirect non-SSL to SSL
server {
    listen 80;
    listen [::]:80;
    server_name pma.myserver.example.com;
    return 301 https://pma.myserver.example.com$request_uri;
}

server {
    listen 443 ssl;
    ssl_certificate     /etc/ssl/pma/pma.crt;
    ssl_certificate_key /etc/ssl/pma/pma.key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK;
    ssl_prefer_server_ciphers on;

    server_name pma.myserver.example.com;

    # The phpMyAdmin installation
    root /usr/share/phpmyadmin;

    index index.php;

    client_max_body_size 2m;

    charset utf-8;

    access_log /var/log/nginx/pma-access.log;
    error_log /var/log/nginx/pma-error.log warn;

    # Deny access to "hidden" files, including Apache's .htaccess files.
    location ~* (?:^|/)\. {
        deny all;
        access_log off;
        log_not_found off;
    }

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

    location ~ /(libraries|setup) {
        deny all;
        return 404;
    }

    location ~ \.php$ {
        try_files $uri =404;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;

        fastcgi_index index.php;

        include fastcgi.conf;
        fastcgi_pass unix:/var/run/php5-fpm-pma.sock;
    }
}

Notes:

  • This file actually creates two server blocks: the first is for redirecting non-HTTPS traffic to HTTPS.
  • The cipher list (ssl_ciphers) is taken from the Mozilla Wiki's Security/Server Side TLS article. Their recommendation is subject to change.
  • There are many more SSL options that are worth looking into.

Then you must then enable the server block:

sudo ln -s /etc/nginx/sites-available/phpmyadmin.conf /etc/nginx/sites-enabled/phpmyadmin.conf

And reload Nginx's configuration files:

sudo service nginx reload

Configure phpMyAdmin

phpMyAdmin's configuration file is located at /etc/phpmyadmin/config.inc.php (this path is set in /usr/share/phpmyadmin/ libraries/vendor_config.php).

However, some of the configuration files that are included by /etc/phpmyadmin/config.inc.php will not be readable if your PHP-FPM pool runs as a user other than www-data. This is because they're owned by root:www-data. Fix this:

sudo chown root:pma /var/lib/phpmyadmin/config.inc.php
sudo chown root:pma /var/lib/phpmyadmin/blowfish_secret.inc.php
sudo chown root:pma /etc/phpmyadmin/config-db.php

Force using HTTPS while accessing phpMyAdmin by adding the following to /var/lib/phpmyadmin/config.inc.php:

$cfg['ForceSSL'] = true;

Notes

  • When configuring your Nginx server, you should take a look at HTML5 Boilerplate's Nginx Server Configs documentation. It provides some great tips and best practices.
  • For SSL/TLS servers, you should test your configuration with SSL Lab's SSL Server Test. Note that this test will fail if you use a self-signed certificate.
  • Your phpMyAdmin installation should be protected with strong passwords. Ideally, you won't need to expose it to the web.