Today I've finished the first migration of a Magento webshop from version 1.9 to 2.2. Together with this move we are also upgrading the Ubuntu VPS from 14.04 LTS to 16.04 LTS. Double migrations both fun and scary at the same time, so many things can go wrong. The migration to Magento2 involves four important components being;

  • data,
  • extensions,
  • theme,
  • other customisations.

Kickoff!

We kicked of this project with creating a fresh new second VPS. This VPS is based on clean Ubuntu Server 16.04.4 LTS. It has all the updates installed and is configured to be only a SSH server. The first thing to do is apply the some basic hardening of the sever with disabling plain text login & setting up the firewall. To simplify the migration steps, other hardening steps will be applied after the migration.

Step 1: Installing the prerequisites

Logically Magento2 has different prerequisites for version 1 then 2. The way we installed the previous VPS is also different because some of the specific versions are now native available via the APT (Debian - Advanced Package Tool).

1.1: MySQL server 5.7.x

Thanks to Ubuntu 16.04 the installation is this time fairly simple. Compared to Ubuntu 14 the MySQL 5.7 server will come directly from Ubuntu's default package repositories. This means we can use the apt package management suite to complete the installation.

Since this is our first time using apt for this session, we should start off by updating our local package index.

$ sudo apt-get update
$ sudo apt-get install mysql-server

During installation there will be a screen asking to fill in your root password for MySQL. To secure the databases you should use another password then your OS root password. After installation you should verify if MySQL is running.

$ sudo mysql --version

Securing the Initial MySQL Accounts

The mysql.user grant table defines the initial MySQL user accounts and their access privileges. Current versions of MySQL 5.7 create only a 'root'@'localhost' account, but for earlier versions, there might be multiple accounts. It's always a good thing to verify that the anonymous users access is disallowed and the test database is dropped.

$ mysql -u root -p
Enter password: *******
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.xx-xubuntu0.16.x.x (Ubuntu)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

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

mysql> SELECT User, Host, HEX(authentication_string) FROM mysql.user;
+-----------+-----------+----------------------------------+
| User      | Host      | HEX(authentication_string)       |
+-----------+-----------+----------------------------------+
| root      | localhost | 2A******83741                    |
| mysql.sys | localhost | 2A******84552                    |
+-----------+-----------+----------------------------------+
2 rows in set (0.01 sec)

mysql> DROP USER ''@'localhost';
ERROR 1396 (HY000): Operation DROP USER failed for ''@'localhost'

mysql> DELETE FROM mysql.db WHERE Db LIKE 'test%';
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> DROP DATABASE test;
ERROR 1008 (HY000): Can't drop database 'test'; database doesn't exist

mysql> \q
Bye

Create the Magento database & user

Magento of course has it's own database and the best practice is to create a new user for it. Never use the root user for this. To create the user and database, login MySQL and execute the following commands.

$ mysql -u root -p
Enter password:

mysql> CREATE USER magentodbuser@localhost IDENTIFIED BY '*******';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE DATABASE mage_db;
Query OK, 1 row affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON mage_db.* TO magentodbuser@localhost IDENTIFIED BY '*******';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> \q
Bye

This finishes the installation of the MySQL server. This configuration is enough for Magento to work.

1.2: Nginx

In order to display Magento application to our site visitors, we are going to employ Nginx, a modern, efficient web server.

We can install the webserver:

$ sudo apt-get install nginx

Verifying the installed version of Nginx

$ nginx -v
nginx version: nginx/1.10.3 (Ubuntu)

On Ubuntu 16 LTS, Nginx is configured to start running upon installation. We've already configured the UFW firewall, which means you don't have to change anything here.

1.3: PHP 7.1

Next step is to install PHP. Since Magento 2.2 we can use the latest version of PHP, which is version 7.1.x

Since Nginx does not contain native PHP processing like some other web servers, we will need to install php-fpm, which stands for "fastCGI process manager". We need to tell Nginx to pass PHP requests to this software for processing.

PHP 7.1 is not part of the standard Ubuntu repository. Therefore we need to add a private repository. The repository from Ondřej Surý is very know, safe and recognized. To add the ppa we need to execute three commands. The first command is to install libraries required to run the add-apt-repository command. The third to update apt with new available packages.

$ sudo apt install software-properties-common
$ sudo add-apt-repository ppa:ondrej/php
$ sudo apt update

Magento 2.2.x requires a list of PHP plugins, which can be installed in one command. The installation will pull in the necessary PHP core files and set everything up. Do this by typing:

$ sudo add-apt-repository ppa:ondrej/php
$ sudo apt-get install php-fpm php7.1-common php7.1-gd php7.1-mysql php7.1-mcrypt php7.1-curl php7.1-intl php7.1-xsl php7.1-mbstring php7.1-zip php7.1-iconv php7.1-soap

Optimise the PHP settings for Magento

To optimise the way PHP works we need to adjust parameters in the PHP configuration settings file. The adjustment needs to happen in both /cli & /fpm folders. There are two different php.ini files. The example below descibes only the fpm folder, you need to execute the exact same steps for the cli!

$ cd /etc/php/7.1/fpm/
$ sudo cp php.ini php.ini.bak
$ sudo nano php.ini

Adjust the following settings:

  • cgi.fix_pathinfo = 0 (uncomment this line)
  • memory_limit = 2G
  • date.timezone = Europe/Amsterdam (uncomment this line + your server location time zone)
  • opcache.enable = 1 (uncomment this line)
  • opcache.memory_consumption = 768 (uncomment this line)
  • opcache.interned_strings_buffer = 12 (uncomment this line)
  • opcache.max_accelerated_files = 60000 (uncomment this line)
  • opcache.validate_timestamps = 0 (uncomment this line)
  • opcache.save_comments = 1 (uncomment this line)
  • opcache.fast_shutdown = 1 (uncomment this line)

use CTRL+w to search for parameter and adjust the values as described above. Save the file, test the new configuration and restart the php7.0-fpm service.

Before we are going to test the configuration there is one file extra to edit beging the 10-opcache.ini file located in the conf.d folder. The reason for editing this file is to disable the option zend_extention=opcache.so, becuase it breakes the estimate-shipping-methods functionality. The config should be this;

; zend_extention=opcache.so
$ sudo php-fpm7.1 -t
[23-Dec-2017 21:09:44] NOTICE: configuration file /etc/php/7.1/fpm/php-fpm.conf test is successful
$ sudo service php7.1-fpm restart

1.4: Composer

For the Magento2 installation I'd like to use composer. Composer is an application-level package manager for the PHP. By default composer is not installed on Ubuntu, but to validate this just enter:

$ composer

If that command didn't respond correctly you still need to install the composer

$ sudo apt-get install curl git
$ curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer

Step 2: Setting up Nginx

Letting Magento2 work out of the box requires configuration to be set in the config file of Nginx beging used on the particular domain used. We do not change the nginx.conf, but create a copy of the default config in the sites-available folder.

$ cd /etc/nginx/sites-available/
$ sudo cp default magento2-shop.nl
$ sudo nano magento2-shop.nl

Copy the following example and adjust the lines where magento-shop.nl is mentioned. Of course for SSL part you need to create certificates at a certificate authority like letsencrypt.org. Hereby the example file I use in as starting point for setting up the final configuration. It's based on the example configuration supplied by Magento. Safe the configuration file CTRL+X and test then create a symlink in the sites-enabled folder.

$ cd ..
$ cd sites-enabled
$ sudo ln -s /etc/nginx/sites-available/magento2-shop.nl /etc/nginx/sites-enabled/magento2-shop.nl
$ sudo nginx -t

After a successful test restart nginx

$ sudo services nginx restart

Now you are ready to start installing Magento2.

Step 3: Install Magento2 with composer:

Before we can install Magento2 it's very handy to create a Magento file system owner. Magento file system owner is another term for the command-line user. This means a separate account and creates a extra level of security. To create a user on Ubuntu, enter the following command as a user with root privileges:

$sudo adduser <username>
Adding user `magento_user' ...
Adding new group `magento_user' (1001) ...
Adding new user `magento_user' (1001) with group `magento_user' ...
Creating home directory `/home/magento_user' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for mage
Enter the new value, or press ENTER for the default
	Full Name []: Magento file system user
	Room Number []:
	Work Phone []:
	Home Phone []:
	Other []:
Is the information correct? [Y/n] Y

Now put the Magento file system owner in the web server’s group

To put the Magento file system owner in the web server’s primary group, enter the following command as a user with root privileges:

$ sudo usermod -g www-data <username>

To confirm your Magento user is a member of the web server group, enter the following command:

$ groups <user name>

A sample result follows: magento_user : www-data
To complete the task, restart the web server:

$ sudo service nginx restart

To be able to install Magento2 with this user we need to change the owner on this folders.

$ sudo chown magento_user:www-data httpsdocs/

Now login as this user, because with this user we need to install Magento2. On the VPS where the Magento install is done we can't use the su magento_user command because this is blocked by the VPS provider. Therefore I use command sudo -u. Sudo -u is meant to run the command as a user other than the default target user (usually root).
After login start the composer script to install Magento. Running the script you're prompted to enter your authentication keys. Your public key is your username; your private key is your password.

$ sudo -u magento_user composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition /usr/share/nginx/domain/httpdocs

After downloading the files, we need to set ownership and permissions for the shared group

To set ownership and permissions before you install the Magento2 software, enter the following commands in the order shown:

cd <your Magento install dir>
sudo -u magento_user find var vendor pub/static pub/media app/etc -type f -exec chmod g+w {} \;
sudo -u magento_user find var vendor pub/static pub/media app/etc -type d -exec chmod g+ws {} \;
sudo chown -R magento_user:www-data * -R
sudo -u magento_user  chmod u+x bin/magento

Step 4: Setup Magento2 on the command line

The minimal command for installing setting up magento2 from command line is:

sudo -u magento_user php bin/magento setup:install --db-user=magentodbuser --db-name=mage_db --db-password=nicepasswordformysql --admin-firstname=Volkert --admin-email=hi@mysite.nl --admin-lastname=Paap --admin-password=mymangentopassword --admin-user=mymagentoadminuser --base-url=http://www.mangento-shop.nl --use-secure=1 --base-url-secure=https://www.magento-shop.nl --use-secure-admin=1 --use-rewrites=1

As result you of the executed command get your admin url back which I would suggest to save somewhere. Example of an admin url could be;

admin_blablalb

If you would browse to your shop, you would get a working empty shop ready for the migration and that concludes part 1. In Part two I would describe how the migration can be done.

Top image source https://www.demacmedia.com/