About installation of CentOS, Drupal and company.
CentOS 7
Install CentOS itself and then yum update
or yum upgrade
.
For your convenience install Midnight Commander:
# yum install mc
Usually I'm using VirtualBox with two ethernet adapters - NAT and Host-only. In than case second adapter doesn't start automatically. To enable:
/etc/sysconfig/network-scripts/ifcfg-enp0s8
ONBOOT=yes
firewalld is blocking access. You can disable it at all or add services (rules) like this:
# firewall-cmd --zone=public --permanent --add-service=http # firewall-cmd --zone=public --permanent --add-service=ftp # firewall-cmd --reload
There are problems: old versions of MariaDB and PHP while Nginx is missing.
Nginx installation
a) by adding the "native" repository - file /etc/yum.repos.d/nginx.repo:
[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=1 enabled=1
# rpm --import http://nginx.org/keys/nginx_signing.key
b) from EPEL:
# yum install epel-release
By the way EPEL will be needed later.
Anyway:
# yum install nginx
Service is disabled. To enable:
# systemctl start nginx # systemctl enable nginx
MariaDB installation
To add repository:
# curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash
Or, if it doesn't work, one can create a repository file based on https://mariadb.org/download/?t=repo-config
E.g. /etc/yum.repos.d/mariadb.repo:
# MariaDB 10.4 CentOS repository list # https://mariadb.org/download/ [mariadb] name = MariaDB # rpm.mariadb.org is a dynamic mirror if your preferred mirror goes offline. See https://mariadb.org/mirrorbits/ for details. # baseurl = https://rpm.mariadb.org/10.4/centos/$releasever/$basearch baseurl = https://mirror.docker.ru/mariadb/yum/10.4/centos/$releasever/$basearch module_hotfixes = 1 # gpgkey = https://rpm.mariadb.org/RPM-GPG-KEY-MariaDB gpgkey = https://mirror.docker.ru/mariadb/yum/RPM-GPG-KEY-MariaDB gpgcheck = 1
Install:
# yum install MariaDB-server MariaDB-client
Turn it on:
# systemctl start mariadb # systemctl enable mariadb
Secure:
# mysql_secure_installation
Initially root password is empty, Enter, change (set) it, others answers are Y
.
Database and user for Drupal are need to be created. Go to the MariaDB CLI - mysql
or mysql -p
depending on your settings. Create DB drupal
, user drupal
(password better be stronger) and grant privileges by series of queries:
CREATE DATABASE drupal; CREATE USER drupal@localhost IDENTIFIED BY 'drupal_password'; GRANT ALL PRIVILEGES ON drupal.* to drupal@localhost; FLUSH PRIVILEGES;
Exit - exit
or \q
PHP installation
# yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
If epel-release is not yet added then it will be "pulled" now.
# yum install yum-utils # yum-config-manager --enable remi-php73
(or any other version required)
Warning! yum install php
also installs Apache (httpd) which is not needed.
Base:
# yum install php-fpm
One can (must!) yum install php-cli
.
Example of PHP extensions installation:
# yum install php-gd php-mysqlnd php-curl php-mbstring php-xml
Problem: nginx running under nginx user, but php-fpm - apache. Let's add www-data user In "Ubuntu style":
# useradd -m -d /var/www -s /sbin/nologin -r -p "*" www-data
GID 33 is occupied so just -r
. It is possible to make /var/www manually without -m
and then chown/chmod.
FTP
From EPEL:
# yum install proftpd proftpd-utils
Create FTP user (substitute uid and gid of system user created before):
# ftpasswd --passwd --file=/etc/proftpd.d/ftpd.passwd --name=www-data --uid=996 --gid=994 --home=/var/www --shell=/bin/false
Important! shell is exactly /bin/false
, not /sbin/nologin
. chown ftp:ftp and chmod 400 on password file if you wish.
SELinux is being stubborn:
# setsebool -P allow_ftpd_full_access=1
Edit /etc/proftpd.conf.
"For the sake of beauty":
User ftp Group ftp
Make comment or remove:
- AuthPAMConfig proftpd
- AuthOrder
Insert into server configuration:
AuthUserFile /etc/proftpd.d/ftpd.passwd AuthPAM off AuthOrder mod_auth_file.c
"Webmin-compatible" add to Global section:
RequireValidShell off
Comment Umask or make sure its value is 022 so the rights to new files and directories will be 644 and 755 respectively.
Now it's time for long and hard setting up of services.
PHP-FPM
/etc/php-fpm.d/www.conf
user = www-data group = www-data listen = /run/php-fpm/www.sock listen.owner = www-data listen.group = www-data
chown -R
on /var/lib/php and /var/log/php-fpm
There is warning if group other than root permitted to write into logging directory.
/etc/php.ini
cgi.fix_pathinfo=0
If you wish:
expose_php = Off
memory_limit
display_errors
display_startup_errors
post_max_size
upload_max_filesize
max_file_uploads
allow_url_fopen = Off
Enable and start service.
Nginx
/etc/nginx/nginx.conf
user www-data;
https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/
GET FIXED
Configure Nginx e.g. /etc/nginx/conf.d/drupal.conf:
server { server_name drupal.example.com; listen 80; root /var/www/drupal; ## <-- Your only path reference. location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; log_not_found off; access_log off; } # Very rarely should these ever be accessed outside of your lan location ~* \.(txt|log)$ { allow 192.168.0.0/16; deny all; } location ~ \..*/.*\.php$ { return 403; } location ~ ^/sites/.*/private/ { return 403; } # Block access to scripts in site files directory location ~ ^/sites/[^/]+/files/.*\.php$ { deny all; } # Allow "Well-Known URIs" as per RFC 5785 location ~* ^/.well-known/ { allow all; } # Block access to "hidden" files and directories whose names begin with a # period. This includes directories used by version control systems such # as Subversion or Git to store control files. location ~ (^|/)\. { return 403; } location / { # try_files $uri @rewrite; # For Drupal <= 6 try_files $uri /index.php?$query_string; # For Drupal >= 7 } location @rewrite { rewrite ^/(.*)$ /index.php?q=$1; } # Don't allow direct access to PHP files in the vendor directory. location ~ /vendor/.*\.php$ { deny all; return 404; } # In Drupal 8, we must also match new paths where the '.php' appears in # the middle, such as update.php/selection. The rule we use is strict, # and only allows this pattern with the update.php front controller. # This allows legacy path aliases in the form of # blog/index.php/legacy-path to continue to route to Drupal nodes. If # you do not have any paths like that, then you might prefer to use a # laxer rule, such as: # location ~ \.php(/|$) { # The laxer rule will continue to work if Drupal uses this new URL # pattern with front controllers other than update.php in a future # release. location ~ '\.php$|^/update.php' { # Security note: If you're running a version of PHP older than the # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini. # See http://serverfault.com/q/627903/94922 for details. # regex to split $uri to $fastcgi_script_name and $fastcgi_path fastcgi_split_path_info ^(.+\.php)(/.+)$; # Check that the PHP script exists before passing it try_files $fastcgi_script_name =404; # Bypass the fact that try_files resets $fastcgi_path_info # see: http://trac.nginx.org/nginx/ticket/321 set $path_info $fastcgi_path_info; fastcgi_param PATH_INFO $path_info; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; # Block httpoxy attacks. See https://httpoxy.org/. fastcgi_param HTTP_PROXY ""; fastcgi_intercept_errors on; # PHP socket location. fastcgi_pass unix:/run/php-fpm/www.sock; } # Fighting with Styles? This little gem is amazing. # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6 location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7 try_files $uri @rewrite; } # Handle private files through Drupal. Private file's path can come # with a language prefix. location ~ ^(/[a-z\-]+)?/system/files/ { # For Drupal >= 7 try_files $uri /index.php?$query_string; } location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { try_files $uri @rewrite; expires max; log_not_found off; } }
So the "sources" are in /var/www/drupal directory.
Since we have changed user, the service most likely needs to be restarted.
# systemctl restart nginx
SELinux
Again (and again)!
Install utilities:
# yum install policycoreutils-python
Allow write:
# semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/drupal/sites/all(/.*)?" # semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/drupal/sites/default/files(/.*)?"
Apply:
# restorecon -r /var/www/drupal/sites
Check if correct context has been established:
# ls -Z /var/www/drupal/sites/all # ls -Z /var/www/drupal/sites/default/files
Conclusion
Generally speaking this completes the stack setup - site should work. Next comes the creative stage for which my guide no longer apply.