In this how-to I will do all steps of a “fresh install of Orocommerce 4.2 on Ubuntu 20.04 LTS. You need to be able to administer an Unbutu or other Linux server and be able to use the text editors (vi, nano or what ever you like). If you can’t: STOP HERE and find somebody who can.
Orocommerce is quite a bit resource consuming so I created a “test server” on my VMWare machine with the following settings:
- 4 Virtual CPUs
- 4 GB of memory
- SSD Disks (hardware mirrored)
Installing Ubuntu 20.04 will not be described here. I installed my server “straight forward” with only OpenSSH as extra package.
Create DNS record for your server
First step is to create a DNS record for your server and make sure that the DNS changes are synced to all DNS servers.
Update the Ubuntu server
sudo apt-get update sudo apt-get -y dist-upgrade --fix-missing sudo apt-get -y upgrade --fix-missing sudo apt-get -y autoremove sudo apt-get clean sudo shutdown -r now
Set password for root:
sudo passwd
sudo apt -y install zip npm wget curl gcc g++ make jpegoptim pngquant dirmngr apt-transport-https lsb-release ca-certificates
Install Chrony NTP Deamon
Whenever you do e-commerce it is a good idea to keep the time of your server as close as possible to the real time. Chrony is a NTP (Network Time Protocol) deamon which does that. Facebook uses Chrony for their servers, so why should you not? 🙂
sudo apt -y install chrony
Check wether the chrony deamon is syncing with other NTP servers. After a couple of minutes you want to see a server with a * or ^* in front of it:
chronyc sources
Install nodejs
Orocommerce needs nodejs 12. Because I like my software to run the latest versions, I installed the latest version which is at the time of writing this post version 14.
cd ~
curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
Inspect the contents of the downloaded script with nano (or your preferred text editor):
nano nodesource_setup.sh
When you are satisfied that the script is safe to run, exit your editor, then run the script with sudo:
sudo bash nodesource_setup.sh
The PPA will be added to your configuration and your local package cache will be updated automatically. You can now install the Node.js package in the same way you normally install packages:
sudo apt install nodejs
Verify that you’ve installed the new version by running node with the -v version flag:
node -v
Install some needed packages:
Install MySQL server
To install the MySQL server issue the following command:
sudo apt install mysql-server
It is always a good idea to secure the mysql directly
sudo mysql_secure_installation
The MySQL deamon can valuate password strength.
VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?
Press y|Y for Yes, any other key for No:
If you know what your doing and trust the other sysadmins you work with you can safely answer N here.
Now set the MySQL root password and write it down in a secure place or store it in a password manager.
Remove anonymous users? (Press y|Y for Yes, any other key for No) :
Answer: Y
Disallow root login remotely? (Press y|Y for Yes, any other key for No) :
Answer: Y
Remove test database and access to it? (Press y|Y for Yes, any other key for No) :
Answer: Y
Reload privilege tables now? (Press y|Y for Yes, any other key for No) :
Answer: Y
Configure the MySQL Server
To store supplementary characters (such as 4-byte emojis), configure the options file to use the utf8mb4 character
Add the following code under [client] to /etc/mysql/debian.cnf
[client]
default-character-set = utf8mb4
Add the following code to /etc/mysql/mysql.conf.d/mysql.cnf
[mysql]
default-character-set = utf8mb4
Add the following code to /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
optimizer_search_depth = 0
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
default-authentication-plugin=mysql_native_password
It is recommended to use SSD’s to store the application data in the MySQL 8.X database. However, if you run your server on HDD and not SDD’s you need to also add the following to this file under [mysqld]:
[mysqld]
innodb_file_per_table = 0
wait_timeout = 28800
For the changes to take effect, restart MySQL server by running:
sudo systemctl enable mysql sudo systemctl restart mysql
Login the MySQL server as root:
sudo mysql -u root -p
Create the MySQL user which will access the database from the website:
mysql> CREATE USER orocomm@localhost IDENTIFIED BY 's0m€$€cretP@$$w0rD';
Query OK, 0 rows affected (0.02 sec)
Store the password in a secured location, for instance a password manager.
Create the database:
mysql> CREATE DATABASE orocomm CHAR SET utf8;
Query OK, 1 row affected, 1 warning (0.02 sec)
Grant access on the database by the user:
mysql> GRANT ALL ON orocomm.* TO orocomm@localhost;
Query OK, 0 rows affected (0.03 sec)
Enable start of the MySQL server at server boot and restart the MySQL server
sudo systemctl enable mysql
sudo systemctl restart mysql
Install Apache Webserver, Certbot and PHP
Install the software:
sudo apt -y install software-properties-common sudo add-apt-repository -y ppa:ondrej/php sudo apt update sudo apt -y upgrade sudo apt -y install apache2 certbot python3-certbot-apache php7.4 php7.4-fpm php7.4-cli php7.4-pdo php7.4-mysqlnd php7.4-xml php7.4-soap php7.4-gd php7.4-zip php7.4-intl php7.4-mbstring php7.4-opcache php7.4-curl php7.4-bcmath php7.4-ldap php7.4-pgsql php7.4-dev php7.4-imap php7.4-tidy
Enable the some Apache modules:
sudo a2enmod rewrite headers proxy_fcgi setenvif http2
Enable http2
sudo a2enmod http2
Enable the PHP FPM module:
sudo a2enconf php7.4-fpm
Enable the automatic start of both the PHP FPM and Apache webserver:
sudo systemctl enable php7.4-fpm
sudo systemctl enable apache2
Restart PHP and the Apache Webserver:
sudo systemctl restart php7.4-fpm
sudo systemctl restart apache2
Configure PHP
In /etc/php/7.4/fpm/php.ini change the following parameters:
memory_limit = 1024M realpath_cache_size=4096K realpath_cache_ttl=600 opcache.enable=1 opcache.enable_cli=0 opcache.memory_consumption=512 opcache.interned_strings_buffer=32 opcache.max_accelerated_files=32531 opcache.save_comments=1
At the end of this file add
catch_workers_output = yes
For the changes to take effect, restart PHP-FPM by running:
sudo systemctl restart php7.4-fpm
Install Composer v2
Install composer:
cd ~
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php
php -r "unlink('composer-setup.php');"
sudo mv composer.phar /usr/bin/composer
Install Docker and Docker Compose
Install docker:
sudo apt -y install docker.io docker-compose
sudo usermod -aG docker $(whoami)
sudo systemctl enable --now docker
sudo systemctl start docker
Install Symfony Server and enable TLS
cd ~ sudo apt -y install libnss3-tools wget https://get.symfony.com/cli/installer -O - | bash echo 'PATH="$HOME/.symfony/bin:$PATH"' >> ~/.bashrc source ~/.bashrc symfony server:ca:install
Install Orocommerce Community using Composer
cd /var/www sudo mkdir oroshop sudo chown yourusername. oroshop
Create a project and download the necessary files:
composer create-project oro/commerce-crm-application oroshop
Some important choices have to be made here: You can change the admin URL for example so it is much harder to guess for hackers.
database_driver (pdo_mysql): database_host ('%env(ORO_DB_HOST)%'): localhost database_port ('%env(ORO_DB_PORT)%'): 3306 database_name ('%env(ORO_DB_NAME)%'): orocomm database_user ('%env(ORO_DB_USER)%'): orocomm database_password ('%env(ORO_DB_PASSWORD)%'): s0m€$€cretP@$$w0rD database_server_version ('%env(ORO_DB_VERSION)%): database_driver_options ({ }): mailer_transport ('%env(ORO_MAILER_DRIVER)%'): mailer_host ('%env(ORO_MAILER_HOST)%'): mailer_port ('%env(ORO_MAILER_PORT)%'): mailer_encryption ('%env(ORO_MAILER_ENCRYPTION)%'): mailer_user ('%env(ORO_MAILER_USER)%'): mailer_password ('%env(ORO_MAILER_PASSWORD)%'): websocket_bind_address (0.0.0.0): websocket_bind_port (8080): websocket_frontend_host (''): websocket_frontend_port (8080): websocket_frontend_path (''): websocket_backend_host (''): websocket_backend_port (8080): websocket_backend_path (''): websocket_backend_transport (tcp): websocket_backend_ssl_context_options ({ }): web_backend_prefix (/admin): /admin_blurp session_handler (session.handler.native_file): secret ('%env(ORO_SECRET)%'): installed (null): assets_version (null): assets_version_strategy (time_hash): message_queue_transport (dbal): message_queue_transport_config (null): enable_price_sharding ('%env(bool:ORO_ENABLE_PRICE_SHARDING)%'): deployment_type (null): liip_imagine.jpegoptim.binary (null): liip_imagine.pngquant.binary (null): env(ORO_DB_HOST) (127.0.0.1): env(ORO_DB_PORT) (null): 3306 env(ORO_DB_NAME) (b2b_crm_dev): orocomm env(ORO_DB_USER) (root): orocomm env(ORO_DB_PASSWORD) (null): s0m€$€cretP@$$w0rD env(ORO_DB_VERSION) (null): env(ORO_MAILER_DRIVER) (sendmail): env(ORO_MAILER_HOST) (127.0.0.1): env(ORO_MAILER_PORT) (null): env(ORO_MAILER_ENCRYPTION) (null): env(ORO_MAILER_USER) (null): env(ORO_MAILER_PASSWORD) (null): env(ORO_SECRET) (ThisTokenIsNotSoSecretChangeIt): env(ORO_ENABLE_PRICE_SHARDING) ('0'):
Change directory to the oro installation directory
cd oroshop
Run the installer
php bin/console oro:install --env=prod --timeout=2000
Make sure you type something usefull at the “Application URL” part: If you don’t, you can start all over again
Administration setup. Application URL (http://localhost): https://shop.yourdomain.com Organization name (ORO): ABC Username (admin): thebestadminintheworld Email: thebestadminintheworld@yourdomain.com First name: your_firstname Last name: your_lastname Password: Formatting Code (en): Language (en): Load sample data (y/n): y
Warm the API cache
php bin/console oro:api:doc:cache:clear --env=prod
Configure Apache 2.4
Create a virtual webserver configuration file for Apache:
sudo nano /etc/apache2/sites-available/shop.yourdomain.com.conf
Change the name of the “shop.yourdomain.com” to the domain name of your website
Add the following to this file:
<VirtualHost *:80> ServerName shop.yourdomain.com #ServerAlias www.<your-domain-name> DirectoryIndex index.php DocumentRoot /var/www/oroshop/public <Directory /var/www/oroshop/public> # enable the .htaccess rewrites AllowOverride All Require all granted </Directory> ErrorLog /var/log/apache2/shop.yourdomain.com_error.log CustomLog /var/log/apache2/shop.yourdomain.com_access.log combined </VirtualHost>
Replace <application-root-folder> with the absolute path to the Oro application. Replace <your-domain-name> with the configured domain name that is used for the Oro application.
Disable the default site and enable shop.yourdomain.com:
sudo a2dissite 000-default sudo a2ensite shop.yourdomain.com
Reload apache:
sudo systemctl reload apache2
Have a look at the log file to check wether there are any errors reloading apache2
tail /var/log/syslog
Get the SSL certificate
I use the free Let’s Encrypt SSL cetrificates for my servers.
sudo certbot --apache
Go through all the steps…
sudo systemctl restart apache2
Have a look at the syslog to double check that Apache starts normally:
tail /var/log/syslog
Change the permissions and ownership
Set the correct ownership and permissions:
sudo chown -R www-data. /var/www/oroshop
Set up cron
Orocommerce needs a cron job to be fired every minute. To schedule execution of the oro:cron command every-minute,
sudo -u www-data -e
add the following line to crontab file:
*/1 * * * * php /var/www/oroshop/bin/console oro:cron --env=prod > /dev/null
If you installed orocommerce in an other locat replace with an absolute path to the installed Oro application.
Install Supervisord
Install supervisord:
sudo apt -y install supervisor
Create a configuration file:
sudo nano /etc/supervisor/conf.d/oroshop.conf
Add the following to this file:
[program:oro_web_socket]
command=php ./bin/console gos:websocket:server --env=prod
numprocs=1
autostart=true
autorestart=true
directory=/var/www/oroshop
user=www-data
redirect_stderr=true
[program:oro_message_consumer]
command=php ./bin/console oro:message-queue:consume --env=prod
process_name=%(program_name)s_%(process_num)02d
numprocs=5
autostart=true
autorestart=true
directory=/var/www/oroshop
user=www-data
redirect_stderr=true
Enable supervisord at boot and restart supervisord
sudo systemctl enable supervisor
sudo systemctl restart supervisor
Now watch supervisord for a couple of minutes by repeating:
sudo supervisorctl status
This is what you want to see after a couple of minutes:
$ sudo supervisorctl status
oro_message_consumer:oro_message_consumer_00 RUNNING pid 54342, uptime 0:03:31
oro_message_consumer:oro_message_consumer_01 RUNNING pid 54343, uptime 0:03:31
oro_message_consumer:oro_message_consumer_02 RUNNING pid 54344, uptime 0:03:31
oro_message_consumer:oro_message_consumer_03 RUNNING pid 54345, uptime 0:03:31
oro_message_consumer:oro_message_consumer_04 RUNNING pid 54346, uptime 0:03:31
oro_web_socket RUNNING pid 54347, uptime 0:03:31
If your message consumers keep restarting and you see errors like below, change “numprocs=5” to “numprocs=1” and retart supervisord
1213 Deadlock found when trying to get lock;
[2021-05-11 02:56:42] console.ERROR: Error thrown while running command "oro:message-queue:consume --env=prod". Message: "An exception occurred while executing 'INSERT IGNORE INTO oro_message_queue_job_unique(name) VALUES(?);' with params ["oro:cron:run_command:oro:cron:imap-sync"]: SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction" {"exception":"[object] (Doctrine\DBAL\Exception\DeadlockException(code: 0): An exception occurred while executing 'INSERT IGNORE INTO oro_message_queue_job_unique(name) VALUES(?);' with params [\"oro:cron:run_command:oro:cron:imap-sync\"]:\n\nSQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction at /var/www/oroshop/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:51, Doctrine\DBAL\Driver\PDO\Exception(code: 40001): SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction at /var/www/oroshop/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDO/Exception.php:18, PDOException(code: 40001): SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction at /var/www/oroshop/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:115)","command":"oro:message-queue:consume --env=prod","message":"An exception occurred while executing 'INSERT IGNORE INTO oro_message_queue_job_unique(name) VALUES(?);' with params [\"oro:cron:run_command:oro:cron:imap-sync\"]:\n\nSQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction"} []