DB-유

Installing the LAMP Stack on CentOS 7

· linux, centos, apache, php

Somebody always turns up with a WordPress site or an internal tool that wants Apache, MariaDB and PHP, so I've built this stack on CentOS 7 more times than I'd like. The base repo gives you Apache 2.4.6, MariaDB 5.5 and PHP 5.4. The first two are fine. PHP 5.4 is out of upstream support and plenty of current apps refuse to run on it, so I take PHP 7.1 from Remi.

I'm assuming sudo, firewalld running, and SELinux left in enforcing mode. Please leave it that way.

Apache

sudo yum -y install httpd
sudo systemctl enable httpd
sudo systemctl start httpd
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Browse to the server IP and you should see the Apache test page. Before going further, set ServerName in /etc/httpd/conf/httpd.conf to stop the startup warning:

ServerName www.example.com:80

I also disable directory listings by removing Indexes from the Options line of the /var/www/html directory block.

MariaDB

sudo yum -y install mariadb-server mariadb
sudo systemctl enable mariadb
sudo systemctl start mariadb
sudo mysql_secure_installation

Answer yes to everything: root password, remove anonymous users, no remote root login, drop the test database. Then give the application its own database and user. I never let an app connect as root:

CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'a-strong-password';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;

MariaDB 5.5 defaults to latin1; add these to /etc/my.cnf.d/server.cnf under [mysqld] so new tables default to UTF-8:

character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

PHP 7.1 from Remi

Remi depends on EPEL, so install both, then enable the PHP 7.1 repo:

sudo yum -y install epel-release
sudo yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
sudo yum -y install yum-utils
sudo yum-config-manager --enable remi-php71
sudo yum -y install php php-mysqlnd php-opcache php-gd php-mbstring php-xml php-json
php -v

The php package pulls in mod_php for Apache. Restart Apache so the module loads:

sudo systemctl restart httpd

Two settings in /etc/php.ini are worth changing right away:

date.timezone = Asia/Seoul
expose_php = Off

A virtual host

I keep sites out of httpd.conf so upgrades and diffs stay clean. Create /etc/httpd/conf.d/example.com.conf:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com/html
    ErrorLog /var/log/httpd/example.com-error.log
    CustomLog /var/log/httpd/example.com-access.log combined

    <Directory /var/www/example.com/html>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

AllowOverride All is needed for applications that ship an .htaccess file with rewrite rules. Create the document root and a test script:

sudo mkdir -p /var/www/example.com/html
echo '<?php phpinfo();' | sudo tee /var/www/example.com/html/info.php
sudo chown -R apache:apache /var/www/example.com
sudo apachectl configtest
sudo systemctl reload httpd

SELinux booleans

If the app needs to send mail, reach a remote database, or write to its own directory (uploads, cache), SELinux blocks it by default. Grant only what's needed. Switching SELinux off is the lazy fix I try never to reach for:

sudo setsebool -P httpd_can_sendmail 1
sudo setsebool -P httpd_can_network_connect_db 1
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/example.com/html/uploads(/.*)?"
sudo restorecon -Rv /var/www/example.com/html/uploads

Is it all talking?

Open http://example.com/info.php and confirm PHP 7.1.x with the mysqlnd and Zend OPcache sections. Then test the database from PHP:

php -r '$m = new mysqli("localhost","appuser","a-strong-password","appdb"); echo $m->server_info, PHP_EOL;'

Delete info.php afterwards. It leaks configuration details, and I've seen it left in place for months.

Errors you'll probably hit

  • AH00558: httpd: Could not reliably determine the server's fully qualified domain name: ServerName isn't set (see Apache above). Harmless, but it buries real errors in the log.
  • The browser downloads .php files or shows raw source: mod_php didn't load. Check httpd -M | grep php and that /etc/httpd/conf.modules.d/15-php.conf exists. Restart, don't reload, Apache after installing PHP.
  • Permission denied on uploads even with chmod 775: SELinux. ausearch -m avc -ts recent shows denied { write } for ... scontext=system_u:system_r:httpd_t. Fix the label as in the SELinux section.
  • SQLSTATE[HY000] [1045] Access denied for user 'appuser'@'localhost': wrong password, or the grant was made for 'appuser'@'%' and MariaDB matched the more specific localhost entry first. SELECT user, host FROM mysql.user; will tell you.

When PHP 7.1 reaches end of life, moving on should just be yum-config-manager --disable remi-php71 --enable remi-php72 and a yum update. Much nicer than a reinstall.