How to install Magento 2.3.x with Nginx (Centos 7)

Installing Magento is challenging but at the same time very easy if done correctly. I am going to show you how to install as well as point out some of the errors and solutions which you might get. Please follow the steps.

I already assume that you have your web server (nginx/apache) configured and running. Here I am going to install it on Nginx with Php-FPM. Magento 2.3.x requires PHP 7.3 or 7.4, recommended is any version of 7.4 other than 7.4.2 as it has some issues.

Note: Make sure you don’t have open_basedir in effect.

Step 1. Create Pool for your user and add to Nginx or php-fpm group

I am going to create a user magento add it to group nginx, if you have already created then please move to step 2.

$ adduser magento -g nginx -d /var/www/magento -s /bin/bash
$ passwd magento

So we have created user magento and added it to group nginx with root directory as /var/www/magento. Now lets add to it php-fpm pool.

First, copy the content of your default pool file (www.conf) from /etc/php-fpm.d/* and create a new one named magento.conf.

$ cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/magento.conf

Now edit the newly created file magento.conf and make sure you have modified the below statement according to your preference.

[magento]
user = magento
group = nginx
listen.owner = magento
listen.group = nginx
listen = /var/run/php-fpm/magento.sock
pm = ondemand
pm.max_children = 50
pm.process_idle_timeout = 10s
pm.max_requests = 500
chdir = /var/www/magento

At this point chown the magento directory to correct user:group and then login from your magento user into ssh and perform following commands.

$ whoami
magento
$ pwd
/var/www/magento

Step 2: Get the Access Keys from Magento Marketplace

As you can see, I am now logged in as magento user into SSH, and before proceeding any further with the installation, we must get Keys from Magento Market place i.e.

Magento Portal > Market Place > My Profile > Choose Magento 2 > Create a New Access Key

Here, your public key will be used as USERNAME, and private key as PASSWORD in the upcoming commands.

Screenshot 1

Screenshot 2

Step 3: Configure Composer

You can either install composer and move it to /usr/local/bin/ to use it globally or you can just use the composer in the current root directory of magento user. I am going to use composer in the root directory of Magento, if you do the same please skip moving it.

Note: Although you can download the Magento file and install via that, but I recommend using composer.

$ curl -sS https://getcomposer.org/installer | php
$ mv composer.phar /usr/local/bin/composer <-- you can skip it

Make sure composer is installed correctly:

$ whoami
magento
$ php composer.phar

Step 4: Download and Install Magento 2

Now download the Magento 2, and when asked for username, please enter your PUBLIC key, for password please enter your PRIVATE key.

$ composer create-project --repository=https://repo.magento.com/ magento/project-community-edition=VERSION [YOUR_DIRECTORY]

Once Its downloaded, execute the following commands to install Magento

$ bin/magento setup:install --base-url=‘http://www.example.com/
–base-url-secure=‘https://www.example.com/
–backend-frontname=‘admin’
–db-host=‘localhost’ --db-name=‘YOUR.DB.NAME’ --db-user=‘YOUR.DB.USER’
–db-password=‘YOUR.DB.PASSWORD’ --admin-firstname=‘JOHN’
–admin-lastname=‘DOE’ --admin-email=‘YOUR@DOMAIN.COM’
–admin-user=‘admin’ --admin-password=‘YOUR.ADMIN.PASSWORD’ --language=‘en_US’
–currency=‘USD’ --timezone=‘UTC’ --use-rewrites=1 --use-secure-admin=1 --use-secure=1

Step 5: Configure Nginx to work with Magento 2

For your magento store, I am assuming example.com as your company domain. Please replace it with your domain name.

Now we are going to configure Nginx for magento user. Edit and paste following config file to your /etc/nginx/conf.d/magento.conf file and restart nginx.

$ vi /etc/nginx/conf.d/magento.conf

Please copy the below content, edit it according to your need and paste it in magento.conf.

server {
listen 80;
server_name example.com;
root /var/www/example;
return 301 https://www.example.com$request_uri;
}
server {
listen 80;
server_name www.example.com;
root /var/www/example;
return 301 https://www.example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
keepalive_timeout 70;
root /var/www/example;
return 301 https://www.example.com$request_uri;
gzip on;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
ssl_protocols TLSv1.2;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4:!3DES;
ssl_dhparam /etc/nginx/conf.d/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_session_tickets off;
ssl_session_cache shared:SSL:10m;
}
server {
listen 443 ssl http2;
server_name www.example.com;
keepalive_timeout 70;

gzip on;
# modsecurity on;
# modsecurity_rules_file /etc/nginx/modsec/main.conf;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
ssl_protocols TLSv1.2;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4:!3DES;
ssl_dhparam /etc/nginx/conf.d/dhparam.pem;
ssl_prefer_server_ciphers on;
ssl_session_tickets off;
ssl_session_cache shared:SSL:10m;
add_header X-Frame-Options “DENY”;
add_header X-Content-Type-Options nosniff;
charset UTF-8;
autoindex off;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
error_page 419 = @magento;
proxy_set_header X-Forwarded-Proto $scheme;
location ~ /. {deny all;}
location / {
root /var/www/example;
try_files $uri $uri/ $uri.html $uri.php?$args;
index index.php index.html;
add_header Strict-Transport-Security “max-age=63072000; includeSubdomains” always;
location /pub/ {
location /pub/media/ {
location /pub/media/customer/ {deny all;}
location /pub/media/downloadable/ {deny all;}
location /pub/media/import/ {deny all;}
location /pub/media/custom_options/ {deny all;}
location ~ /pub/media/theme_customization/..xml$ {deny all;}
try_files $uri $uri/ /pub/get.php?$args;
location ~
.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
add_header Cache-Control “public”;
add_header X-Frame-Options “SAMEORIGIN”;
expires +1y;
try_files $uri $uri/ /pub/get.php?$args;
}
location ~* .(zip|gz|gzip|bz2|csv|xml)$ {
add_header Cache-Control “no-store”;
add_header X-Frame-Options “SAMEORIGIN”;
expires off;
try_files $uri $uri/ /pub/get.php?$args;
}
}
location /pub/static/ {
#expires max;
location ~ ^/pub/static/version {
rewrite ^/pub/static/(version\d*/)?(.)$ /pub/static/$2 last;
}
location ~
.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
add_header Cache-Control “public”;
add_header X-Frame-Options “SAMEORIGIN”;
expires +1y;
if (!-f $request_filename) {
rewrite ^/pub/static/(version\d*/)?(.)$ /pub/static.php?resource=$2 last;
}
}
location ~
.(zip|gz|gzip|bz2|csv|xml)$ {
add_header Cache-Control “no-store”;
add_header X-Frame-Options “SAMEORIGIN”;
expires off;
if (!-f $request_filename) {
rewrite ^/pub/static/(version\d*/)?(.)$ /pub/static.php?resource=$2 last;
}
}
if (!-f $request_filename) {
rewrite ^/pub/static/(version\d
/)?(.)$ /pub/static.php?resource=$2 last;
}
add_header X-Frame-Options “SAMEORIGIN”;
}
add_header X-Frame-Options “SAMEORIGIN”;
location ~ ^/pub/errors/.
.(xml|phtml)$ {deny all;}
location /pub/errors/ {try_files $uri =404;}
location = /pub/cron.php {deny all;}
}
}
location ~ (index|get|static|report|404|503|phpinfo).php$ {return 419;}
if (-e $request_filename) {return 403;}
rewrite / /index.php last;
}

location /.user.ini { deny all; }

location @magento {
root /var/www/example;
fastcgi_pass php-fpm;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
if ($request_uri ~ ^/([^?]*).php($|?)) { return 302 /$1?$args; }
try_files $uri = 404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_intercept_errors on;
fastcgi_param PHP_FLAG “session.auto_start=off \n suhosin.session.cryptua=off”;
fastcgi_connect_timeout 600s;
fastcgi_read_timeout 600s;
fastcgi_buffers 1024 4k;
include fastcgi_params;
}

gzip_disable “msie6”;
gzip_comp_level 6;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types
text/plain
text/css
text/js
text/xml
text/javascript
application/javascript
application/x-javascript
application/json
application/xml
application/xml+rss
image/svg+xml;
gzip_vary on;
# Banned locations (only reached if the earlier PHP entry point regexes don’t match)
location ~* (.php$|.phtml$|.htaccess$|.git) {
deny all;
}
# deny access to .htaccess files, if Apache’s document root
# concurs with nginx’s one
#
location ~ /.ht {
deny all;
}
}

Step 6: Edit “php.ini” to configure PHP

Make sure the following parameters in your php.ini file are similar to whats given below.

memory_limit = 2G
upload_max_filesize = 256M,
zlib.output_compression = on
max_execution_time = 18000,
date.timezone = UTC
opcache.save_comments = 1

Finally restart your nginx and php-fpm.

$ systemctl restart php-fpm
$ systemctl restart nginx

OPTIONAL: (Install sample data)

php bin/magneto sampledata:deploy
php bin/magento module:enable --all
php bin/magento setup:upgrade

you can disable the CSP by following commands, as CSP is really not necessary.

$ bin/magento module:disable Magento_Csp --clear-static-content
$ bin/magento setup:di:compile
$ bin/magento c:c

Step 7: Create Cron for Magento 2

Do not forget to create cron job for magento because several magento features require at least one cron job, which schedules activities to occur in the future. You must create the cron job from the magento user in the <root magento directory>.

$ whoami
magento
$ pwd
/var/www/magento
$ bin/magento cron:install --force

You can verify by viewing the crontab

$ crontab -l

You can confirm the installation by visiting your website. If you face any issue or error please comment below. : )