Prestashop demo deployment with own module using Docker Compose

Piotr Bracha
4 min readNov 1, 2021

--

Last time I need to provide some environment for testing purposes own module to the Prestashop software. I decided to use Docker to accomplish the task. Below are configuration files I created.

  1. Docker-compose.yml:
version: "3.7"

services:
nginx:
image: nginx:stable
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- prestashop

certbot:
image: certbot/certbot
volumes:
- web-root:/var/www/html
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nginx
command: certonly --webroot --webroot-path=/var/www/html --email mail@example.com --agree-tos --no-eff-email --keep-until-expiring -d demo.example.com -d www.demo.example.com
#--keep-until-expiring for --staging in the final version on the line above

prestashop:
image: prestashop/prestashop:latest
volumes:
- ./my_module:/var/www/html/modules/my_module
restart: always
environment:
PS_DOMAIN: demo.example.com
PS_FOLDER_ADMIN: ${PS_FOLDER_ADMIN}
PS_FOLDER_INSTALL: ${PS_FOLDER_INSTALL}
PS_ENABLE_SSL: 1
PS_INSTALL_AUTO: 1
PS_ERASE_DB: 1
PS_INSTALL_DB: 1
DB_SERVER: ${DB_SERVER}
DB_USER: ${DB_USER}
DB_PASSWD: ${DB_PASSWD}
DB_NAME: ${DB_NAME}
DB_PREFIX: ${DB_PREFIX}
ADMIN_MAIL: ${ADMIN_MAIL}
ADMIN_PASSWD: ${ADMIN_PASSWD}
depends_on:
- mysql

mysql:
image: mysql:5.7
restart: always
volumes:
- mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}

volumes:
certbot-etc:
certbot-var:
web-root:
mysql:

Ok, so what happened above? Nginx container will be a proxy in this case. I created three named volumes shared with Certbot container to allow, using LetsEncrypt, provide nice green padlock to my demo shop:

  • web-root
  • certbot-etc
  • certbot-var

“./nginx-conf” is a bind mount used to store my domain’s vhost file. Few words more later about this config.

Certbot container executes specific command. Generally speaking it allows automatically obtain the certificate for my domain. I used webroot plugin, because — quoting from LE documentation — I prefer not to stop the webserver during the certificate issuance process. Above, in the code snippet, is the comment pointing out which option should be used in the final version of the executed command.

--staging - allows to request many times (without being blocked) for "staging" certificate, it does not give you green padlock in the browser, you need to use --keep-until-expiring to get that

Prestashop container uses bind mount to attach “my_module” directory to the container. It’s required later to install automatically the module. “Environment” part shows used variables stored in the “.env” file, which is in the same directory. The main goal is to reset the shop two times each day, so I need to use PS_ERASE_DB and PS_INSTALL_DB variables, which allow drop current database and create one during installation process.

MySQL container uses named volume to store data. Nothing special here. At the end of the docker-compose.yml is part with all named volumes. It’s required by docker-compose specification.

Ok, let’s go further. The “.env” file. Inside, variables need to be declared as below:

.env
# Prestashop
PS_FOLDER_ADMIN=name_of_the_folder_admin <-- it need to be changed from default "admin" due to security reasons, because this will be the name of shop's backoffice exhibited in the url
PS_FOLDER_INSTALL=name_of_the_folder_install <-- changing determined also by security reasons

DB_SERVER=mysql <-- name of the mysql container
DB_USER=your_db_user
DB_PASSWD=user_password
DB_NAME=some_db_name
DB_PREFIX=prefix_ <-- good to change default prefix due to security reasons

ADMIN_MAIL=demo@example.com <-- mail used to login to the backoffice
ADMIN_PASSWD=some_difficult_password

# Database
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=some_db_name
MYSQL_USER=your_db_user
MYSQL_PASSWORD=user_password

Now it’s the time for nginx vhost file:

server {
server_name demo.example.com www.demo.example.com;

location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}

location / {
return 301 https://$host$request_uri;
}
}

server {
listen 443 ssl http2;
server_name demo.example.com www.demo.example.com;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;

ssl_certificate /etc/letsencrypt/live/demo.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/demo.example.com/privkey.pem;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;

proxy_pass http://prestashop;
}
}

First server block is configured for port 80 (you don’t have to explicitely declare this port). First location block inside is required by Certbot’s webroot plugin. Second location block is simple http to https redirection.

Second server block I created based on Mozilla SSL Configurator Generator. I added location block which allows prestashop container to be visible under https://demo.example.com. More informations about proxing and headers here, here and here.

We have done our docker-compose configuration and proxy. Let’s go further to the bash script which automatically resets our demo shop and installs our module:

#!/bin/bash

cd /path/to/project/main/dir

DOCKER_COMPOSE=$(whereis docker-compose | awk '{ print $2 }')

echo "restarting services"
$DOCKER_COMPOSE down
sleep 10
$DOCKER_COMPOSE up -d
sleep 10
$DOCKER_COMPOSE exec -T prestashop bash -c 'rm -r /var/www/html/install.lock'

#need to sleep a little to allow containers be fully operable
sleep 30

echo "module installation"
$DOCKER_COMPOSE exec -T prestashop bash -c 'php bin/console prestashop:module install my_module'
$DOCKER_COMPOSE exec -T prestashop bash -c 'rm -r /var/www/html/var/cache/pro*'
echo "finished module installation"
echo "finished the process"

Some thoughts about the script:

  • each “docker-compose exec” need to be executed with “-T” parameter if we plan to use crontab, because we do not want to interactive shell
  • removing “install.lock” file after “up” containers is required due to some kind of bug with Prestashop image which leads to looping installation process (shop is deployed but prestashop’s software think it isn’t and tries install it). Interestingly this problem does not happen every time.
  • installing module without clearing cache breaks the shop (I’m not making this up!); there are two directories “prod” and strange looking “pro_”, both need to be deleted

Finally script is added to the crontab of local user:

0 */12 * * * /path/to/project/main/dir/deploy_script.sh > /path/to/project/main/dir/file.log 2>&1

Earlier I mentioned about main goal — reset the shop two times per day. Crontab is useful to this task. I decided to add results of script execution to the logfile and also redirect stderr and stdout to the same file. More informations nicely described for example here.

Disclaimer: This tutorial was done on the fresh Ubuntu Server 20.04.3 LTS with newest version of Docker and Docker-Compose.

--

--