How To Install Linux, Nginx, MySQL (MariaDB), PHP-FPM (LEMP) Stack on CentOS Stream 9

main menu
dnf mariadb

This article presents how to install a Web server with application back-end PHP and database back-end MySQL using MariaDB. All the software installed throughout this article is from the CentOS Stream 9 official repositories including the EPEL repository. The machine is installed with a minimal installation of CentOS Stream 9 and there is a how-to here – Network installation of CentOS Stream 9 (20220606.0) – minimal server installation.
Here are the steps to perform:

  1. Install, configure and start the database MariaDB.
  2. Install, configure and start the PHP-FPM and PHP cli.
  3. Install, configure and start the Web server Nginx.
  4. Configure the system – firewall and SELinux.
  5. Test the installation with a phpMyAdmin installation.
  6. Bonus – Nginx HTTPS with SSL certificate – self-signed and letsencrypt.

STEP 1) Install, configure and start the database MariaDB.

First, install the MariaDB server by:

dnf install -y mariadb-server

To configure the MariaDB server, the main file is /etc/my.cnf, which just includes all files under the folder /etc/my.cnf.d/

[root@srv ~]# cat /etc/my.cnf
#
# This group is read both both by the client and the server
# use it for options that affect everything
#
[client-server]

#
# include all files from the config directory
#
!includedir /etc/my.cnf.d

[root@srv ~]# ls -altr /etc/my.cnf.d/
total 32
-rw-r--r--.  1 root root  295 Mar 25  2022 client.cnf
-rw-r--r--.  1 root root  120 May 18 07:55 spider.cnf
-rw-r--r--.  1 root root  232 May 18 07:55 mysql-clients.cnf
-rw-r--r--.  1 root root  763 May 18 07:55 enable_encryption.preset
-rw-r--r--.  1 root root 1458 Jun 13 13:24 mariadb-server.cnf
-rw-r--r--.  1 root root   42 Jun 13 13:29 auth_gssapi.cnf
drwxr-xr-x.  2 root root 4096 Oct  6 06:34 .
drwxr-xr-x. 81 root root 4096 Oct  6 06:34 ..

The most important file for the MariaDB server is /etc/my.cnf.d/mariadb-server.cnf, where all the server options are included. Under section “[mysqld]” add options to tune the MariaDB server. Supported options could be found here: https://mariadb.com/kb/en/mysqld-options/
Add the following options under “[mysqld]” in /etc/my.cnf.d/mariadb-server.cnf

# Generic
skip-external-locking
skip-character-set-client-handshake
skip-name-resolve

key_buffer_size                 = 1024M
sort_buffer_size                = 200K
net_buffer_length               = 64K
read_buffer_size                = 256K
read_rnd_buffer_size            = 512K
myisam_sort_buffer_size         = 256M
thread_cache_size               = 100
max_connections                 = 1000
max_heap_table_size             = 512M
open_files_limit                = 30000
max_allowed_packet              = 16M
myisam-recover-options  = BACKUP

sync_binlog=0
sql_mode="NO_ENGINE_SUBSTITUTION"

# InnoDB
innodb_buffer_pool_size = 4G
innodb_log_buffer_size = 24M
innodb_log_file_size = 128M
innodb_flush_method = O_DIRECT
innodb_file_per_table
innodb_flush_log_at_trx_commit = 0
innodb_lock_wait_timeout = 150
innodb_thread_concurrency = 0

The most important options is innodb_buffer_pool_size, which should be 70% of available RAM (for machines with low amount of RAM, those above the 32G the percentage should be higher) or the size of the database.
It’s worth noting that no additional configuration is required to start the MariaDB server, but it’s good to make some optimization even for a test/staging/dev environment.
Second, start the services and enable it to start on boot. Check if the services has started successfully:

[root@srv ~]# systemctl enable mariadb
Created symlink /etc/systemd/system/mysql.service → /usr/lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/mysqld.service → /usr/lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/multi-user.target.wants/mariadb.service → /usr/lib/systemd/system/mariadb.service.
[root@srv ~]# systemctl start mariadb
[root@srv ~]# systemctl status mariadb
● mariadb.service - MariaDB 10.5 database server
     Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
     Active: active (running) since Thu 2022-10-06 07:04:00 UTC; 5s ago
       Docs: man:mariadbd(8)
             https://mariadb.com/kb/en/library/systemd/
    Process: 3810 ExecStartPre=/usr/libexec/mariadb-check-socket (code=exited, status=0/SUCCESS)
    Process: 3832 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir mariadb.service (code=exited, s>
    Process: 3937 ExecStartPost=/usr/libexec/mariadb-check-upgrade (code=exited, status=0/SUCCESS)
   Main PID: 3921 (mariadbd)
     Status: "Taking your SQL requests now..."
      Tasks: 15 (limit: 23072)
     Memory: 369.3M
        CPU: 1.291s
     CGroup: /system.slice/mariadb.service
             └─3921 /usr/libexec/mariadbd --basedir=/usr

Oct 06 07:04:00 srv mariadb-prepare-db-dir[3871]: you need to be the system 'mysql' user to connec>
Oct 06 07:04:00 srv mariadb-prepare-db-dir[3871]: After connecting you can set the password, if yo>
Oct 06 07:04:00 srv mariadb-prepare-db-dir[3871]: able to connect as any of these users with a pas>
Oct 06 07:04:00 srv mariadb-prepare-db-dir[3871]: See the MariaDB Knowledgebase at https://mariadb>
Oct 06 07:04:00 srv mariadb-prepare-db-dir[3871]: Please report any problems at https://mariadb.or>
Oct 06 07:04:00 srv mariadb-prepare-db-dir[3871]: The latest information about MariaDB is availabl>
Oct 06 07:04:00 srv mariadb-prepare-db-dir[3871]: Consider joining MariaDB's strong and vibrant co>
Oct 06 07:04:00 srv mariadb-prepare-db-dir[3871]: https://mariadb.org/get-involved/
Oct 06 07:04:00 srv mariadbd[3921]: 2022-10-06  7:04:00 0 [Note] /usr/libexec/mariadbd (mysqld 10.>
[root@srv ~]# pstree
systemd─┬─NetworkManager───2*[{NetworkManager}]
        ├─agetty
        ├─anacron
        ├─auditd───{auditd}
        ├─chronyd
        ├─crond
        ├─dbus-broker-lau───dbus-broker
        ├─firewalld───{firewalld}
        ├─irqbalance───{irqbalance}
        ├─mariadbd───7*[{mariadbd}]
        ├─mdadm
        ├─polkitd───5*[{polkitd}]
        ├─rsyslogd───2*[{rsyslogd}]
        ├─sshd───sshd───sshd───bash───pstree
        ├─systemd───(sd-pam)
        ├─systemd-journal
        ├─systemd-logind
        └─systemd-udevd

MariaDB server will accept connections through the Unix socket file: /var/lib/mysql/mysql.sock. If the user wants to accept network connections to the MariaDB server, the following options should be enabled (uncomment it or add it) in /etc/my.cnf.d/mariadb-server.cnf:

bind-address=0.0.0.0

It will accept connections on all network interfaces, if only on a specific one is desired, just add the IP instead of 0.0.0.0.

Secure the installation with the MariaDB tool: mysql_secure_installation. This build-in tool presents several questions, which are considered to make the current installation of MariaDB more secure. By default, the MariaDB root password (the user with all privileges) has no password, so this tool sets root password and more.

[root@srv ~]# mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
haven't set the root password yet, you should just press enter here.

Enter current password for root (enter for none): 
OK, successfully used password, moving on...

Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.

You already have your root account protected, so you can safely answer 'n'.

Switch to unix_socket authentication [Y/n] Y
Enabled successfully!
Reloading privilege tables..
 ... Success!


You already have your root account protected, so you can safely answer 'n'.

Change the root password? [Y/n] Y
New password: 
Re-enter new password: 
Password updated successfully!
Reloading privilege tables..
 ... Success!


By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] Y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

For user convinience, add the root password in /root/.my.cnf as follow and the system root user will enter the MariaDB console without entering a password.

root@srv ~]# cat /root/.my.cnf 
[client]
password="Thiu6je1ba:u4AhNgo0E"
[root@srv ~]# chmod 400 /root/.my.cnf
[root@srv ~]# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 13
Server version: 10.5.16-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> ^DBye
root@srv ~]# 

STEP 2) Install, configure and start the application part – PHP-FPM and PHP cli.

FPM is FastCGI Process Manager, it starts a daemon, which runs a predefined number of PHP-FPM processes and it waits for Unix or TCP/IP connections to process them with PHP processor.
First, install PHP-FPM and PHP cli.

dnf install -y php-fpm php-cli php-pdo php-mbstring php-mysqlnd php-gd php-intl

There are two parts of PHP configuration:

  • PHP configuration – the application, which processes the PHP files. The configuration is in /etc/php.ini and the custom modules configurations are in the directory /etc/php.d/
  • PHP FPM configuration – the process, which controls the execution of the PHP daemon, which process the PHP files. The configuration is in /etc/php-fpm.conf and custom daemons’ configurations (there may be multiple instances of the daemon, each of which will start its own tree of processes) are under /etc/php-fpm.d/. By default, there is only one pool of PHP-FPM processes with configuration file /etc/php-fpm.d/www.conf

PHP configuration

The configuration is in file /etc/php.ini and in general, there are 3 important options:

.....
date.timezone = UTC
.....
memory_limit = 256M
.....
max_execution_time = 60
.....

The file is around 1660 lines with options and comments, but in most cases, the first limits to hit are the above ones. By default, date.timezone is not set and is commented, so comment it out and set a value, the time zone, which used by the date functions – http://php.net/date.timezone. The second memory_limit is how much memory is allowed for each process and the third max_execution_time is how much time is allowed a process to take before being killed by the PHP.

PHP FPM Configuration

/etc/php-fpm.conf – defines global configuration for all pools and includes the files for each pool in /etc/php-fpm.d/. So the first pool, which will start one PHP process tree is in /etc/php-fpm.d/www.conf
Here are the important options, which should be uncommented or modified as follows:

.....
user = nginx
group = nginx
.....
listen.backlog = 1024
.....
pm.max_requests = 20000
.....

Set the user to be nginx, because this Web server will be used. The backlog means how many connections to queue when there are connections to the process, which cannot be processed immediately.
Interesting options to manage the process counts of the PHP processes are: pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers, pm.process_idle_timeout, pm.max_requests (always set a limit to how many requests a process can accept, memory leaks do exists, so restarting a PHP process is a good thing! Be careful, with low values on a busy server.)
The default configuration will accept connections only through the Unix socket file: /run/php-fpm/www.sock. To accept network connections modify the listen and listen.allowed_clients options:

.....
listen="10.10.10.10:9000"
.....
;listen.allowed_clients=
.....

The PHP-FPM will accept network connections from IP 10.10.10.10 on port 9000.
In the configuration file there are many comments, which the user should read, because they may help him to find interesting options like access logging, slow logging, error logging, status and ping pages and more.
Start and enable on boot the PHP-FPM service:

[root@srv ~]# systemctl enable php-fpm
Created symlink /etc/systemd/system/multi-user.target.wants/php-fpm.service → /usr/lib/systemd/system/php-fpm.service.
[root@srv ~]# systemctl start php-fpm
[root@srv ~]# systemctl status php-fpm
● php-fpm.service - The PHP FastCGI Process Manager
     Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; vendor preset: disabled)
     Active: active (running) since Thu 2022-10-06 08:06:42 UTC; 3s ago
   Main PID: 4817 (php-fpm)
     Status: "Ready to handle connections"
      Tasks: 6 (limit: 23072)
     Memory: 10.4M
        CPU: 83ms
     CGroup: /system.slice/php-fpm.service
             ├─4817 "php-fpm: master process (/etc/php-fpm.conf)"
             ├─4818 "php-fpm: pool www"
             ├─4819 "php-fpm: pool www"
             ├─4820 "php-fpm: pool www"
             ├─4821 "php-fpm: pool www"
             └─4822 "php-fpm: pool www"

Oct 06 08:06:42 srv systemd[1]: Starting The PHP FastCGI Process Manager...
Oct 06 08:06:42 srv systemd[1]: Started The PHP FastCGI Process Manager.

There is a master PHP-FPM process, which ran 5 process to accept connections.
Fix the PHP session write permissions with:

[root@srv ~]# ls -altrZ /var/lib/php/
total 24
drwxrwx---.  2 root apache system_u:object_r:httpd_var_run_t:s0 4096 Aug  1 09:42 wsdlcache
drwxrwx---.  2 root apache system_u:object_r:httpd_var_run_t:s0 4096 Aug  1 09:42 session
drwxr-xr-x.  2 root root   system_u:object_r:httpd_var_lib_t:s0 4096 Aug  1 09:42 peclxml
drwxrwx---.  2 root apache system_u:object_r:httpd_var_lib_t:s0 4096 Aug  1 09:42 opcache
drwxr-xr-x.  6 root root   system_u:object_r:httpd_var_lib_t:s0 4096 Oct  6 07:32 .
drwxr-xr-x. 27 root root   system_u:object_r:var_lib_t:s0       4096 Oct  6 08:15 ..
[root@srv ~]# chown root:nginx /var/lib/php/wsdlcache/
[root@srv ~]# chown root:nginx /var/lib/php/session/
[root@srv ~]# chown root:nginx /var/lib/php/opcache/
[root@srv ~]# ls -altrZ /var/lib/php/
total 24
drwxrwx---.  2 root nginx system_u:object_r:httpd_var_run_t:s0 4096 Aug  1 09:42 wsdlcache
drwxr-xr-x.  2 root root  system_u:object_r:httpd_var_lib_t:s0 4096 Aug  1 09:42 peclxml
drwxrwx---.  2 root nginx system_u:object_r:httpd_var_lib_t:s0 4096 Aug  1 09:42 opcache
drwxr-xr-x.  6 root root  system_u:object_r:httpd_var_lib_t:s0 4096 Oct  6 07:32 .
drwxr-xr-x. 27 root root  system_u:object_r:var_lib_t:s0       4096 Oct  6 08:15 ..
drwxrwx---.  2 root nginx system_u:object_r:httpd_var_run_t:s0 4096 Oct  6 09:34 session

The directories’ groups are apache, but nginx is used, that’s why the user should be change. A blank page may be displayed if the PHP-FPM could not write to these directories.
The SELinux permission are fine.

STEP 3) Install, configure and start the Web server Nginx.

First, install the Nginx server.

dnf install -y nginx

The main configuration file is in /etc/nginx/nginx.conf, where are defined the virtual hosts (server sections) for this server. By default, only the HTTP (without SSL certificate) is defined, the SSL one is commented.
By default, Nginx defines default domain “_”, which accepts all no other sector is defined. So if the user wants to have a custom server block, the best it to copy the whole default block and modify the following options: server_name, root, include at least.

]
.....
    server {
        listen       80;
        listen       [::]:80;
        server_name  example.mydomain.com;
        root         /var/www/html/example.mydomain.com;

        # Load configuration files for the example.mydomain.com server block.
        include /etc/nginx/sites.d/example.mydomain.com.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
.....

Make sure to create the /etc/nginx/sites.d/example.mydomain.com.conf. It is a good idea always to split different server blocks in different configuration files or at least, the specific options. It should be noted that to process a PHP-FPM requests, the above block must defines a similar location directive (mentioned below), so just copying the /etc/nginx/default.d/php.conf to /etc/nginx/sites.d/example.mydomain.com.conf is enough to begin with.
Installing the Nginx at the last step will ensure the existence of two important files for the PHP-FPM.
There are two more important directories:

  • modular configuration files/etc/nginx/conf.d/ all files with extension .conf. Configuration file for multiple server sectors (i.e. for multiple virtual hosts). The options in these files will tune and be visible for all domains. At present, there is only one file – /etc/nginx/conf.d/php-fpm.conf :
    # PHP-FPM FastCGI server
    # network or unix domain socket configuration
    
    upstream php-fpm {
            server unix:/run/php-fpm/www.sock;
    }
    

    It defines an upstream group of servers for the application back-end, i.e. PHP-FPM, which accept connections through Unix socket file /run/php-fpm/www.sock. The socket file is the same as in the configuration section of PHP-FPM.

  • default server block configuration files – /etc/nginx/default.d/. Configuration options only for one server block, i.e. virtual host (domain) – the default one, which accepts all requests if no other server section for the requested domain is defined. There is only one file /etc/nginx/default.d/php.conf, which define a section instructing Nginx to open a connection through the defined upstream to the PHP-FPM process:
    # pass the PHP scripts to FastCGI server
    #
    # See conf.d/php-fpm.conf for socket configuration
    #
    index index.php index.html index.htm;
    
    location ~ \.(php|phar)(/.*)?$ {
        fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;
    
        fastcgi_intercept_errors on;
        fastcgi_index  index.php;
        include        fastcgi_params;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO $fastcgi_path_info;
        fastcgi_pass   php-fpm;
    }
    

    So if a request to a file with extension “.php” in the server including this location, the request will be handled to the upstream server and the PHP-FPM process will process the request.

For completeness, this article should show how to add a configuration for the domain and not to use the default domain (and server block section). Even the PHP-FPM should be removed from the default, because the default should serve only static content. So here is the final configuration with a fake domain:

  • /etc/nginx/nginx.conf configuration:
    .....
        server {
            listen       80;
            listen       [::]:80;
            server_name  _;
            root         /usr/share/nginx/html;
    
            # Load configuration files for the default server block.
            # include /etc/nginx/default.d/*.conf;
    
            error_page 404 /404.html;
            location = /404.html {
            }
    
            error_page 500 502 503 504 /50x.html;
            location = /50x.html {
            }
        }
    
        server {
            listen       80;
            listen       [::]:80;
            server_name  example.mydomain.com;
            root         /var/www/html/example.mydomain.com;
    
            # Load configuration files for the default server block.
            include /etc/nginx/sites.d/example.mydomain.com.conf;
    
            error_page 404 /404.html;
            location = /404.html {
            }
    
            error_page 500 502 503 504 /50x.html;
            location = /50x.html {
            }
        }
    .....
    
  • Remove the PHP-FPM location configuration for the default server block and add it to the example.mydomain.com.
    mv /etc/nginx/default.d/php.conf /etc/nginx/sites.d/example.mydomain.com.conf
    

Finally, test the configuration and start the service. Enable it to start on boot.

[root@srv ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@srv ~]# systemctl start nginx
[root@srv ~]# systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
[root@srv ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
    Drop-In: /usr/lib/systemd/system/nginx.service.d
             └─php-fpm.conf
     Active: active (running) since Thu 2022-10-06 09:20:03 UTC; 9s ago
   Main PID: 5106 (nginx)
      Tasks: 3 (limit: 23072)
     Memory: 2.9M
        CPU: 68ms
     CGroup: /system.slice/nginx.service
             ├─5106 "nginx: master process /usr/sbin/nginx"
             ├─5107 "nginx: worker process"
             └─5108 "nginx: worker process"

Oct 06 09:20:03 srv systemd[1]: Starting The nginx HTTP and reverse proxy server...
Oct 06 09:20:03 srv nginx[5104]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Oct 06 09:20:03 srv nginx[5104]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Oct 06 09:20:03 srv systemd[1]: Started The nginx HTTP and reverse proxy server.

STEP 4) Configure the system – firewall and SELinux

By default, CentOS Stream 9 uses firewalld service and firewall-cmd cli to control it. Allow HTTP trafffic to the server:

[root@srv ~]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s3
  sources: 
  services: cockpit dhcpv6-client ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
[root@srv ~]# firewall-cmd --permanent --add-service=http
success
[root@srv ~]# firewall-cmd --reload
success
[root@srv ~]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s3
  sources: 
  services: cockpit dhcpv6-client http ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:

If the web root directories is under /var/www there is no need to tune the SELinux. If the user want to change to another location not under /var/www, the SELinux label httpd_sys_content_t must be added to the parent directory.
For example, if the web root directories are under /mnt/storage/www, the following commands should be issued:

[root@srv ~]# semanage fcontext -a -t httpd_sys_rw_content_t '/mnt/storage/www(/.*)?'
[root@srv ~]# restorecon -Rv /mnt/storage/www
Relabeled /mnt/storage/www from unconfined_u:object_r:mnt_t:s0 to unconfined_u:object_r:httpd_sys_rw_content_t:s0

Otherwise, the SELinux will block any web request to the /mnt/storage/www.

STEP 5) Test all the three components – Nginx, PHP-FPM and MariaDB.

First test is Nginx+PHP-FPM and it purpose is to show phpinfo() page. Create a file /var/www/html/example.mydomain.com/test.php with the content as shown below and then set the owner to “nginx:nginx”.

[root@srv ~]# cat /var/www/html/example.mydomain.com/test.php
<?php
phpinfo();
[root@srv ~]# chown -R nginx:nginx /var/www/html/example.mydomain.com

main menu
phpinfo page

Second, test the Nginx+PHP-FPM + MariaDB, i.e. the connectivity to the database from the application layer PHP-FPM.
Just download the phpMyAdmin package from https://files.phpmyadmin.net/phpMyAdmin/5.2.0/phpMyAdmin-5.2.0-all-languages.zip or the latest version. Unpack, add default config and load it in the browser:

[root@srv ~]# cd /var/www/html/example.mydomain.com
[root@srv example.mydomain.com]# wget https://files.phpmyadmin.net/phpMyAdmin/5.2.0/phpMyAdmin-5.2.0-all-languages.zip
--2022-10-06 09:28:27--  https://files.phpmyadmin.net/phpMyAdmin/5.2.0/phpMyAdmin-5.2.0-all-languages.zip
Resolving files.phpmyadmin.net (files.phpmyadmin.net)... 185.76.8.4, 2a02:6ea0:d900::3
Connecting to files.phpmyadmin.net (files.phpmyadmin.net)|185.76.8.4|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14112668 (13M) [application/zip]
Saving to: ‘phpMyAdmin-5.2.0-all-languages.zip’

phpMyAdmin-5.2.0-all-lan 100%[=================================>]  13.46M  6.30MB/s    in 2.1s    

2022-10-06 09:28:30 (6.30 MB/s) - ‘phpMyAdmin-5.2.0-all-languages.zip’ saved [14112668/14112668]

[root@srv example.mydomain.com]# unzip phpMyAdmin-5.2.0-all-languages.zip 
Archive:  phpMyAdmin-5.2.0-all-languages.zip
   creating: phpMyAdmin-5.2.0-all-languages/
 extracting: phpMyAdmin-5.2.0-all-languages/.rtlcssrc.json
.....
.....
  inflating: phpMyAdmin-5.2.0-all-languages/yarn.lock  
[root@srv example.mydomain.com]# mv phpMyAdmin-5.2.0-all-languages phpmyadmin
[root@srv example.mydomain.com]# cd phpmyadmin
[root@srv example.mydomain.com]# cp config.sample.inc.php config.inc.php

Then open the browser and login with MariaDB root account and the password set in the (STEP 1). The phpMyAdmin should be located in http://example.mydomain.com/phpmyadmin/.

main menu
phpMyAdmin

Bonus) Nginx HTTPS with SSL certificate – self-signed and letsencrypt.

Two types of certificate generations for the HTTPS server block will be presented in this section:

  1. Self-signed certificate. The browsers will report it is unsafe and the user should accept the certificate before viewing the site. It is convinient for development stage.
  2. Letsencrypt certificate – the software needed and how to generate. A free and valid certificate. More info – https://letsencrypt.org/

Generate self-signed certificate

Generate the self-signed certificate and configure the firewall to accept HTTPS connections.

[root@srv ~]# openssl genrsa -out /etc/ssl/nginx/example.mydomain.com.key 4096
[root@srv ~]# openssl req -new -key /etc/ssl/nginx/example.mydomain.com.key -out /etc/ssl/nginx/example.mydomain.com.csr -subj '/C=us/ST=newyork/L=newyork/O=mygroup/OU=servicing/CN=example.mydomain.com/emailAddress=admin@mydomain.com'
[root@srv ~]# openssl x509 -req -days 365 -in /etc/ssl/nginx/example.mydomain.com.csr -signkey /etc/ssl/nginx/example.mydomain.com.key -out /etc/ssl/nginx/example.mydomain.com.crt
[root@srv ~]# chmod 400 /etc/ssl/nginx/*
[root@srv ~]# ls -altr /etc/ssl/nginx/
total 20
drwxr-xr-x. 3 root root 4096 Oct  6 11:10 ..
-r--------. 1 root root 3268 Oct  6 11:11 example.mydomain.com.key
-r--------. 1 root root 1765 Oct  6 11:12 example.mydomain.com.csr
drwxr-xr-x. 2 root root 4096 Oct  6 11:13 .
-r--------. 1 root root 2049 Oct  6 11:13 example.mydomain.com.crt
[root@srv ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@srv ~]# systemctl restart nginx
[root@srv ~]# firewall-cmd --permanent --add-service=https
success
[root@srv ~]# firewall-cmd --reload
success

Here is the Nginx server block (in /etc/nginx.nginx.conf below the above two server blocks) for the HTTPS connections:

.....
    server {
        listen       443 ssl http2;
        listen       [::]:443 ssl http2;
        server_name  example.mydomain.com;
        root         /var/www/html/example.mydomain.com;

        ssl_certificate "/etc/ssl/nginx/example.mydomain.com.crt";
        ssl_certificate_key "/etc/ssl/nginx/example.mydomain.com.key";
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout  10m;
        ssl_ciphers PROFILE=SYSTEM;
        ssl_prefer_server_ciphers on;

        # Load configuration files for the default server block.
        include /etc/nginx/sites.d/example.mydomain.com.conf;

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
.....

Test and restart the Nginx web server.

[root@srv ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@srv ~]# systemctl restart nginx

The phpMyAdmin should be located in https://example.mydomain.com/phpmyadmin/.

main menu
https phpMyAdmin

Letsencrypt certificate

Install the needed software. certbot is the command-line tool to generate, renewn and manage Let’s Encrypt SSL Certificates.

dnf install -y epel-release
dnf install -y certbot

The domain example.mydomain.com must have an accessible Internet IP, which the servers behind the letsencrypt organization would access using HTTP/HTTPS.

[root@srv ~]# certbot certonly --webroot -w /var/www/html/example.mydomain.com -d example.mydomain.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for example.mydomain.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.mydomain.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.mydomain.com/privkey.pem
This certificate expires on 2023-01-04.
These files will be updated when the certificate renews.

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The Nginx configuration in /etc/nginx/nginx.conf looks like:

.....
    server {
        listen       443 ssl http2;
        listen       [::]:443 ssl http2;
        server_name  example.mydomain.com;
        root         /var/www/html/example.mydomain.com;

        ssl_certificate "/etc/letsencrypt/live/example.mydomain.com/fullchain.pem";
        ssl_certificate_key "/etc/letsencrypt/live/example.mydomain.com/privkey.pem";
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout  10m;
        ssl_ciphers PROFILE=SYSTEM;
        ssl_prefer_server_ciphers on;

        # Load configuration files for the default server block.
        include /etc/nginx/sites.d/example.mydomain.com.conf;

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
.....

Essensially the same with the self-singed one, but with modified the path of ssl_certificate and ssl_certificate_key.
Test and restart the Nginx web server.

[root@srv ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@srv ~]# systemctl restart nginx

The phpMyAdmin should be located in https://example.mydomain.com/phpmyadmin/, but this time the SSL certificate will be valid for example.mydomain.com and no errors or crititcal warnings will receive the users of the site.

Leave a Reply

Your email address will not be published. Required fields are marked *