--- tags: magento GA: UA-167433668-1 title: Magento 2.4 Installation & Extension Tutorial description: How to install and setup Magento 2.4 on Ubuntu 18.04, and create your own extension. image: https://static.magento.com/sites/default/files8/2020-08/21998_dx_Commercial%20Social%20Share%20Image%20-%20Magento.jpg --- Introduction: [Magento 2.4 Introduction](https://hackmd.io/@rgbkoi/BySSWQ6ku) **Content** [TOC] --- Environment: - DigitalOcean LAMP droplet - 1 GB/1 (shared) CPU - 25 GB SSD - 1000 GB transfer - Ubuntu 20.04 - access via ssh + rsa key only (no password) - static ip: [188.166.223.100](http://188.166.223.100) :::spoiler **personal setup** - add the following line to `/etc/bash.bashrc`: ``` alias lh='ls -lh' ``` - uncomment the following line in `~/.bashrc`: ``` force_color_prompt=yes ``` - add/create `/etc/vim/vimrc.local`: ``` set relativenumber set title ``` ::: Prerequisites --- 1. LAMP stack (comes with the droplet) - install php extensions: ``` # apt install -y php7.4-pdo php7.4-mysqlnd php7.4-opcache php7.4-xml php7.4-gd php7.4-devel php7.4-mysql php7.4-intl php7.4-mbstring php7.4-bcmath php7.4-json php7.4-iconv php7.4-soap # service apache2 restart ``` - enable the extensions? - find the php settings file using `php --ini | grep "Loaded Configuration File"`, edit the file according to [this](https://devdocs.magento.com/guides/v2.4/install-gde/prereq/php-settings.html#php-required-set) - setup magento database according to [this](https://devdocs.magento.com/guides/v2.4/install-gde/prereq/mysql.html#instgde-prereq-mysql-config) 2. Elasticsearch - choices: - install on same host (resource-heavy, impacts performance) - install on different host (hassle) - [elastic cloud service](https://cloud.elastic.co/home) (needs money, has 14-day trial) :heavy_check_mark: - setup: - elastic stack (elasticsearch & kibana) - I/O optimized - provider: azure - region: tokyo - version: 7.10.2/**7.9.3**/6.8.13 (Magento 2.4 is only tested with ElasticSearch 7.6.x) - Username: elastic Password: mDlI7KIvNVV************* - endpoint: [https://7829e64f95bc4f32b4875e61d98fcc69.japaneast.azure.elastic-cloud.com:9243](https://7829e64f95bc4f32b4875e61d98fcc69.japaneast.azure.elastic-cloud.com:9243) ![where to copy enpoint](https://i.imgur.com/UQxlD50.png) - verify elastic search installation: <pre><font color="#8AE234"><b>root@magento</b></font>:<font color="#729FCF"><b>~</b></font># curl -XGET --user elastic:mDlI7KIvNVV************* &apos;https://7829e64f95bc4f32b4875e61d98fcc69.japaneast.azure.elastic-cloud.com:9243/_cat/health?v&amp;pretty&apos; epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent 1611508837 17:20:37 7829e64f95bc4f32b4875e61d98fcc69 green 3 2 26 13 0 0 0 0 - 100.0%</pre> - add the following lines to `/etc/environment` ``` elastichost='https://7829e64f95bc4f32b4875e61d98fcc69.japaneast.azure.elastic-cloud.com' elasticport='9243' elasticuser='elastic' elasticpw='mDlI7KIvNVV*************' ``` - so that we can use `$elasticpw` in place of the password. <pre><font color="#8AE234"><b>root@magento</b></font>:<font color="#729FCF"><b>~</b></font># curl -XGET --user $elasticuser:$elasticpw $elastichost:$elasticport&apos;/_cat/health?v&amp;pretty&apos; epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent 1611510162 17:42:42 7829e64f95bc4f32b4875e61d98fcc69 green 3 2 28 14 0 0 0 0 - 100.0% </pre> 3. Setup Magento file system owner - Add user (malleo) to the web server group `www-data`, use `--disabled-password` so that this user can only log in via ssh rsa. - Copy `root`'s ssh config (incl. authorized keys) to `/home/<user>/`, and give the user access to their `.ssh` folder. - extend write access of `/var/www/html` to the `www-data` group <pre><font color="#8AE234"><b>root@magento</b></font>:<font color="#729FCF"><b>~</b></font># adduser malleo --ingroup www-data --disabled-password Adding user `malleo&apos; ... Adding new user `malleo&apos; (1000) with group `www-data&apos; ... Creating home directory `/home/malleo&apos; ... Copying files from `/etc/skel&apos; ... Changing the user information for malleo Enter the new value, or press ENTER for the default Full Name []: Malleo Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] Y <font color="#8AE234"><b>root@magento</b></font>:<font color="#729FCF"><b>~</b></font># cp ~/.ssh /home/malleo/ <font color="#8AE234"><b>root@magento</b></font>:<font color="#729FCF"><b>~</b></font># chown -R malleo:www-data /home/malleo/.ssh <font color="#8AE234"><b>root@magento</b></font>:<font color="#729FCF"><b>~</b></font># chmod g+w -R /var/www/html </pre> 4. Setup necessary `.ssh/config` on local machine, then connect via ssh as the new user. Or, just switch to the new user: `su <user>`. Install Magento --- 1. Install composer (~~[steps](https://getcomposer.org/download/)~~ Magento 2.4 does not support composer 2.x) `# apt install composer -y` (this will install Composer 1.10) 2. Get magento - register an account at [magento marketplace](https://account.magento.com/applications/customer/create/) if you haven't already - create [access keys](https://marketplace.magento.com/customer/accessKeys/) (public key will be used as Username, private key as Password in the following step) ([details](https://devdocs.magento.com/guides/v2.3/install-gde/prereq/connect-auth.html)) - cd to web server's docroot, use `composer` to install Magento. Provide Username and Password from previous step when prompted. <pre><font color="#8AE234"><b>malleo@magento</b></font>:<font color="#729FCF"><b>/var/www/html</b></font>$ composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition magento2.4 <font color="#4E9A06">Creating a &quot;magento/project-community-edition&quot; project at &quot;./magento2.4&quot;</font> <span style="background-color:#C4A000"><font color="#2E3436">Warning from repo.magento.com: You haven&apos;t provided your Magento authentication keys. For instructions, visit https://devdocs.magento.com/guides/v2.3/install-gde/prereq/connect-auth.html</font></span> Authentication required (<font color="#4E9A06">repo.magento.com</font>): Username: 9ad314f5ee397972**************** Password: Do you want to store credentials for repo.magento.com in /home/malleo/.config/composer/auth.json ? [Yn] Y <font color="#4E9A06">Installing magento/project-community-edition (2.4.1)</font> - Installing <font color="#4E9A06">magento/project-community-edition</font> (<font color="#C4A000">2.4.1</font>): Downloading (<font color="#C4A000">100%</font>) <font color="#4E9A06">Created project in /var/www/html/magento2.4</font> <font color="#4E9A06">Loading composer repositories with package information</font> <span style="background-color:#C4A000"><font color="#2E3436">Warning from https://repo.packagist.org: You are using an outdated version of Composer. Composer 2.0 is now available and you should upgrade. See https://getcomposer.org/2</font></span> <font color="#4E9A06">Updating dependencies (including require-dev)</font> ... <font color="#4E9A06">Writing lock file</font> <font color="#4E9A06">Generating autoload files</font> <font color="#4E9A06">90 packages you are using are looking for funding.</font> <font color="#4E9A06">Use the `composer fund` command to find out more!</font> PHP CodeSniffer Config <font color="#4E9A06">installed_paths</font> <font color="#C4A000">set to</font> <font color="#4E9A06">../../magento/magento-coding-standard,../../phpcompatibility/php-compatibility</font></pre> - Process may get killed at <font color="#4E9A06">`Updating dependencies (including require-dev)`</font> if the machine has insufficient memory. Possible solutions: ([ref](https://stackoverflow.com/questions/20667761/composer-killed-while-updating)) - stop `mysql` temporarily: `service mysql stop` - [add temporary swap](https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-20-04) (the swap file created does not persist through reboot) - if it says `xxx` extension is missing, do `apt install php-xxx` as root. 3. Install Magento (using CLI) - to run magento from anywhere, add the following line to `/etc/bash.bashrc` or `~/.bash_aliases`: ``` alias magento='/var/www/html/magento2/bin/magento' ``` - then, install magento ```bash magento setup:install --base-url=http://188.166.223.100/magento2/ \ --db-host=localhost --db-name=magento --db-user=magento --db-password=magento \ --admin-firstname=malleo --admin-lastname=s \ --admin-email=******@gmail.com --admin-user=malleo --admin-password=********** \ --language=en_US --currency=TWD --timezone=Asia/Taipei --use-rewrites=1 \ --search-engine=elasticsearch7 \ --elasticsearch-host=$elastichost --elasticsearch-port=$elasticport \ --elasticsearch-enable-auth=1 --elasticsearch-username=$elasticuser --elasticsearch-password=$elasticpw ``` - if success, a backend URI will be given (e.g. `admin_k6iTr`) - if failed and need to redo install, append `--cleanup-database` 4. Verify installation - go to [website](http://188.166.223.100) ![](https://i.imgur.com/YtdyR43.png) - if no style is displayed, try running `magento setup:static-content:deploy -f` then hit <kbd>ctrl</kbd>+<kbd>F5</kbd> ([ref](https://magento.stackexchange.com/questions/136879/accidentally-deleted-htaccess-file-inside-pub-static-folder)) - log into admin at `http://<your-website-address>/<admin-backend>` ![magento admin login panel](https://i.imgur.com/1AsrPv7.png =300x) - if asked to setup two-factor but the host machine does not have a mail server, do the following to disable the tfa. ([ref](https://community.magento.com/t5/Installing-Magento-2-x/An-E-mail-was-sent-to-configure-Two-Factor-Authorization-in/td-p/458322)) ``` $ magento module:disable Magento_TwoFactorAuth $ magento cache:flush ``` 5. Add sample data :::warning **do not** add your own product, category, etc before installing sample data. db conflict may occur otherwise. ::: use composer to install sample data, then do `setup:upgrade` to update database etc. ([ref](https://devdocs.magento.com/guides/v2.4/install-gde/install/cli/install-cli-sample-data-composer.html)) ``` $ magento sampledata:deploy $ magento setup:upgrade ``` 6. cleaning up generated files: ``` $ rm -r var/cache/* var/view_preprocessed/* pub/static/adminhtml/* pub/static/frontend/* ``` 7. give access to `www-data`: (need root) ``` # chmod -R g+w var pub generated ``` Module development --- ref: [mage plaza](https://www.mageplaza.com/magento-2-module-development/), [module root directory](https://devdocs.magento.com/guides/v2.4/extension-dev-guide/prepare/prepare_file-str.html#root-directory-location), [module file structure](https://devdocs.magento.com/guides/v2.4/extension-dev-guide/build/module-file-structure.html#module-file-structure) There is two possible module root directory: 1. `<magento root>/app` Recommended. Works with git. Magento core will be in this directory if installed via `git clone`. - modules: `app/code` - themes: `app/design` - language: `app/i18n` 2. `<magento root>/vendor` Magento core and third-party components will be in this directory if installed via `composer create-project`. This directory is ignored by `git`. In this example, the module `hello world` will live in `app/code/Malleo/HelloWorld`. :::info replace `Malleo` with your Vendor name (e.g. your name or your company name) in the following example. ::: ### 1. Create configuration file The module's config files live in `<module root>/etc`. ([ref](https://devdocs.magento.com/guides/v2.4/extension-dev-guide/build/required-configuration-files.html#use-etc-for-your-configuration-files)) ```bash # create module's root directory and etc directory # use switch -p to create parent directory if it does not exist $ mkdir -p app/code/Malleo/HelloWorld/etc ``` Add the following content to `<module root>/etc/module.xml` to define the module's name. ```xml= <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="Malleo_HelloWorld" setup_version="1.0.0"> </module> </config> ``` ### 2. Register the module The module must be registered to Magento system by a `<module root>/registration.php` file, which uses `ComponentRegistrar::register();`. Add the following content to `app/code/Malleo/HelloWorld/registration.php`: ([ref](https://devdocs.magento.com/guides/v2.4/extension-dev-guide/build/component-registration.html#register-modules)) ```php= <?php use Magento\Framework\Component\ComponentRegistrar; ComponentRegistrar::register( ComponentRegistrar::MODULE, 'Malleo_HelloWorld', __DIR__); ``` Verify the module's existence by running `magento module:status`. The module's name should appear under <font color="#4E9A06">`List of disabled modules:`</font> ### 3. Create frontend route The frontend route config file is `<module root>/etc/frontend/routes.xml`. Add the following content so that the (frontend) calls to the module will be routed to `http://<magento base url>/helloworld/...`: ```xml= <?xml version="1.0" ?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <router id="standard"> <route frontName="helloworld" id="helloworld"> <module name="Malleo_HelloWorld"/> </route> </router> </config> ``` ### 4. Implement logic (ref: [Mage Plaza](https://www.mageplaza.com/magento-2-module-development/how-to-create-controllers-magento-2.html)) Add the following to `<module root>/Controller/Index/Index.php`. This class extends `Action`, which will be returned as an instance of `ActionController` when matched by router. `FrontController` will call `dispatch()` on it, which then calls `Action::execute()`. A page will then be created by `PageFactory`. ```php= <?php namespace Malleo\HelloWorld\Controller\Index; use \Magento\Framework\App\Action\Context; use \Magento\Framework\View\Result\PageFactory; class Index extends \Magento\Framework\App\Action\Action { protected $_pageFactory; public function __construct( Context $context, PageFactory $pageFactory) { $this->_pageFactory = $pageFactory; return parent::__construct($context); } public function execute() { return $this->_pageFactory->create(); } } ``` ### 5. Create layout Create a simple layout file `<module root>/view/frontend/layout/helloworld_index_index.xml`, this will be used by `http://<magento base url>/helloworld/index/index`, The Block and template is defined. ```xml= <?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <referenceContainer name="content"> <block class="Malleo\HelloWorld\Block\Index" name="helloworld_index" template="Malleo_HelloWorld::index.phtml" /> </referenceContainer> </page> ``` ### 6. Create the block used in layout The block file should be `<module root>/Block/Index.php`. It has a function that tells you what day it is. ```php= <?php namespace Malleo\HelloWorld\Block; class Index extends \Magento\Framework\View\Element\Template { public function getDayText() { return "Today is " . date("l") . " :)"; } } ``` ### 7. Create the template used in layout Templates live in `<module root>/view/frontend/templates`, and the filename is `index.phtml` as defined earlier. The template displays "Hello World" as level 2 header, and calls the function of the associated Block. ```htmlmixed= <h2>Hello World!</h2> <p><?php echo $this->getDayText(); ?></p> ``` ### 8. Enable the module ref: [magento docs](https://devdocs.magento.com/guides/v2.4/extension-dev-guide/build/enable-module.html) 1. disable cache at `system`->`cache management` in admin 2. enable the module, upgrade db, clear cache ```bash $ magento module:enable --clear-static-content Malleo_HelloWorld $ magento setup:upgrade $ magento cache:clean # or $ magento c:c ``` 3. check status of module: `$ magento module:status Malleo_HelloWorld`, should give output `Module is enabled` 4. enable cache again: `$ magento cache:enable` 5. if module is modified, go to `system->cache management` and refresh cache type `Blocks HTML output` and `Page Cache`. 6. go to `http://<magento base url>/helloworld` or `http://<magento base url>/helloworld/index/index` to see module output. ![](https://i.imgur.com/HBw5BOV.png)