Artykuł przedstawia krok po kroku – jak wdrożyć demonstracyjny sklep internetowy z wykorzystaniem oprogramowania PrestaShop, Docker (Docker Compose), LetsEncrypt Certbot i Nginx. Warto podkreślić, iż sklep będzie cyklicznie resetowany, aby mógł realnie pełnić funkcję demonstracyjną customowego modułu.
Zagadnienia, jakie będą poruszane to:
- Wyjaśnienie konfiguracji zawartej w plikach wykorzystanych do wdrożenia
- Na co zwrócić uwagę w trakcie deploymentu tytułowego stacka
- Automatyczne odnawianie certyfikatu SSL
- Nginx jako proxy dla kontenera dockerowego
- Automatyczne wdrożenie własnego modułu do PrestaShop
Rezultatem wdrożenia będzie sklep internetowy PrestaShop (wraz z bazą danych) zabezpieczony certyfikatem SSL oraz posiadający pełnoprawny backoffice, w którym możemy przeprowadzać jego dalszą konfigurację poprzez np. dodanie produktów. Całość zostanie przeprowadzona z wykorzystaniem kontenerów i Dockera.
Prestashop i Docker – Konfiguracja kontenera Nginxa
W tej sekcji skupimy się na plikach konfiguracyjnych niezbędnych do realizacji wdrożenia. Ich przygotowanie wymaga podstawowej znajomości Nginxa i Certbota. Zatem zaczynajmy!
Na początek skonfigurujemy serwis Nginxa, dzięki któremu sklep będzie widoczny w przeglądarce.
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
Za co odpowiada powyższy fragment kodu?
Kontener Nginx będzie w tym przypadku pełnił rolę serwera proxy. Na początku został wskazany obraz, który zostanie wykorzystany do utworzenia kontenera. Wdrożenia produkcyjne zwykle powinny wykorzystywać wersje stable
. Więcej o wersji stable
oprogramowania dostępne np. tutaj.
Do kontenera zostaną podmontowane pliki przechowujące konfigurację Nginx dla domeny sklepu oraz trzy nazwane wolumeny współdzielone z kontenerem Certbot. Umożliwi to, przy użyciu LetsEncrypt, na szyfrowane połączenie z wykorzystaniem certyfikatu SSL do powstającego demonstracyjnego sklepu:
- web-root
- certbot-etc
- certbot-var
Wewnątrz pliku nginx-conf
znajduje się konfiguracja domeny sklepu składającego się z dwóch bloków server
. Poniżej pierwszy blok:
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; } }
Jest on skonfigurowany dla portu 80, którego zgodnie z dokumentacją nie trzeba jawnie deklarować w dyrektywie listen
:
If the directive is not present then either *:80 is used if nginx runs with the superuser privileges, or *:8000 otherwise.
Pierwszy blok location
jest wymagany przez plugin webroot
Certbota (mający tu zastosowanie fragment dokumentacji). Drugi blok location
to przekierowanie ruchu z HTTP na HTTPS.
Drugi blok server{}
jest nieco bardziej skomplikowany.
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; } }
Powstał w oparciu o Mozilla SSL Configurator Generator, aby zapewnić odpowiedni poziom bezpieczeństwa zestawionego połączenia. Dodany w jego obrębie blok location
zawiera nagłówki umożliwiające zadziałanie serwerowi Nginx jako proxy dla kontenera PrestaShop i wystawienie go pod domeną https://demo.example.com.
Więcej użytecznych informacji dotyczących nagłówków i proxy, na bazie których powstała ta część konfiguracji, można znaleźć tu, tu i tu. W dyrektywie proxy_pass
parametrem jest nazwa serwisu określona w pierwszej linii konfiguracji kontenera PrestaShop.
Prestashop i Docker – bez SSL ani rusz…
Obecnie jesteśmy w epoce “Internetu HTTPS”
. Każda strona powinna być zabezpieczona. Tym bardziej warto to wykonać, ponieważ Google przychylniej patrzy na pozycjonowanie takich stron.
Natomiast nie w każdym przypadku trzeba zakupić certyfikat SSL. Niejednokrotnie wystarczy darmowy, pełnoprawny certyfikat SSL uzyskany z CA LetsEncrypt przy użyciu narzędzia Certbot. Poniżej fragment konfiguracji odpowiadający za uzyskanie certyfikatu SSL dla domeny wdrażanego sklepu.
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 [email protected] --agree-tos --no-eff-email --staging -d demo.example.com -d www.demo.example.com #--keep-until-expiring za --staging w produkcyjnej wersji w linii powyżej
Analogicznie jak w przypadku konfiguracji serwisu Nginxa został wskazany obraz, a następnie wolumeny, o których wspominałem wyżej. Pod nimi jest linia depends_on określająca, że najpierw ma zostać uruchomiony kontener Nginx, a jako drugi w kolejności kontener Certbota.
Cała magia dzieje się po słowie command. Kontener Certbota wykonuje określone polecenie. Ogólnie rzecz biorąc, pozwala ono na automatyczne uzyskanie certyfikatu dla domeny sklepu wskazanej jako parametr.
Najistotniejszym elementem polecenia jest --staging
, umożliwiające wielokrotne uzyskiwanie testowego certyfikatu. Opcja przydaje się przy debugowaniu projektu kiedy to może się przytrafić wielokrotne zatrzymywanie i uruchamianie kontenerów. Niemniej w tym konkretnym przypadku docelowo musi być zamieniona na --keep-until-expiring
dbające o to, by uzyskać prawidłowy certyfikat, a za każdym kolejnym uruchomieniem docker-compose up -d
automatycznie odnowić go jeśli zajdzie taka potrzeba.
Przygotowanie konfiguracji PrestaShop
Kontener PrestaShop korzysta z podmontowanego katalogu z dysku hosta do dołączenia katalogu my_module
do kontenera. Jest on później potrzebny do automatycznej instalacji modułu.
Sekcja Environment
zawiera listę zmiennych, z których część jest wczytywana z pliku .env
znajdującego się w tym samym katalogu co plik docker-compose.yml. Jednym z celów jest resetowanie sklepu dwa razy dziennie, dlatego zostały użyte zmienne PS_ERASE_DB i PS_INSTALL_DB umożliwiające usunięcie bieżącej bazy danych i utworzenie jej ponownie podczas procesu instalacji. Będzie to wykonywane cyklicznie w ramach zadania umieszczonego w crontabie.
Oczywiście, zanim wystartuje kontener PrestaShop, musi być uruchomiony kontener MySQLa. Za co odpowiada wcześniej wspomniana instrukcja depends_on
.
prestashop: image: prestashop/prestashop:1.7.8 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
Nie może być sklepu internetowego PrestaShop bez bazy danych
W przypadku kontenera MySQLa nie ma nic szczególnego. Wskazujemy użyty obraz, wolumin nazwany mający przechowywać konfigurację i kilka zmiennych środowiskowych, które wykorzystuje kontener PrestaShop. Oczywiście nic nie stoi na przeszkodzie by pliki bazy danych podmontować bezpośrednio na dysku hosta. Dzięki temu możemy np. wykonać backup bazy danych w tradycyjny sposób.
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}
Konfiguracja zmiennych środowiskowych w zewnętrznym pliku
Kontenery MySQL i PrestaShop wykorzystują zmienne środowiskowe. Ich wartości nie są jednak jawnie dostępne z poziomu pliku docker-compose.yml, ponieważ znajdują się w pliku .env
. Poniżej fragmenty wraz z opisami.
# Prestashop PS_FOLDER_ADMIN=nazwa_folderu_panelu_admina PS_FOLDER_INSTALL=nazwa_folderu_instalacyjnego DB_SERVER=mysql DB_USER=uzytkownik_bazy_danych DB_PASSWD=haslo_uzytkownika DB_NAME=nazwa_bazy_danych DB_PREFIX=prefix_ [email protected] ADMIN_PASSWD=jakies_trudne_haslo
Ze względów bezpieczeństwa nazwa folderu panelu admina powinna zostać zmieniona z domyślnego admin
, ponieważ będzie to nazwa backoffice sklepu eksponowana w adresie url.
Z podobnych względów należy zmienić nazwę folderu instalacyjnego i prefiks tabel w zmiennej DB_PREFIX. W zmiennej DB_SERVER wskazujemy nazwę kontenera MySQL. Mail określony w zmiennej ADMIN_MAIL będzie służył do logowania do backoffice sklepu.
# Database MYSQL_ROOT_PASSWORD=rootpassword MYSQL_DATABASE=nazwa_bazy_danych MYSQL_USER=uzytkownik_bazy_danych MYSQL_PASSWORD=haslo_uzytkownika
Powyższy fragment dotyczy zmiennych wykorzystywanych przez kontener MySQL.
Czas na moduł do PrestaShop
Przeprowadziliśmy konfigurację docker-compose i nginx proxy oraz zadbaliśmy o certyfikat SSL dla domeny sklepu. Czas na skrypt bash, który automatycznie zresetuje sklep demo i zainstaluje customowy moduł:
#!/bin/bash cd /path/to/project/main/dir DOCKER_COMPOSE=$(whereis docker-compose | awk '{ print $2 }') echo "restarting services" $DOCKER_COMPOSE down $DOCKER_COMPOSE up -d $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"
Kilka słów na temat powyższego skryptu:
- Jeśli planujemy użyć crontaba to każde polecenie
docker-compose exec
musi być wykonywane z parametrem-T
, ponieważ nie chcemy w takim wypadku interaktywnej powłoki. - Usunięcie pliku
install.lock
po wykonaniudocker-compose up -d
jest wymagane ze względu na pewien rodzaj buga z obrazem PrestaShop prowadzącego do zapętlenia procesu instalacji. Polega on na tym, że sklep jest wdrożony, ale oprogramowanie PrestaShop uważa, że nie jest i próbuje go instalować. Co ciekawe, problem ten nie występuje za każdym razem. Natomiast usunięcie tego pliku definitywnie rozwiązuje problem. - Wystąpienie instrukcji
sleep
z parametrem 30 daje czas (30s) na pełne uruchomienie kontenerów, bo tylko wtedy moduł się zainstaluje. - Instalacja modułu bez wyczyszczenia cache psuje sklep (sic!); tworzą się dwa katalogi
prod
i nietypowo wyglądającypro_
. Oba muszą zostać usunięte.
Na koniec skrypt jest dodany do pliku Crontab lokalnego użytkownika:
0 */12 * * * /path/to/project/main/dir/deploy_script.sh > /path/to/project/main/dir/file.log 2>&1
Warto nadmienić, że ewentualne błędy będą w powyższym wpisie crona przekierowywane do pliku file.log
.
Kompletny plik docker-compose.yml do uruchomienia sklepu internetowego PrestaShop za pomocą Docker
Opisane wyżej konfiguracje Nginxa, Certbota, PrestaShop i MySQL muszą zostać uzupełnione o poniższy fragment volumes dodany na samym dole, aby całość była zgodna ze specyfikacją docker-compose:
volumes: certbot-etc: certbot-var: web-root: mysql:
Wtedy powstaje plik, który możemy uruchomić poleceniem docker-compose up -d
:
Docker i Let’s Encrypt – na co zwracać uwagę
Przed wdrożeniem kontenera Certbota umożliwiającego uzyskanie certyfikatu opartego o CA Let’s Encrypt należy zastanowić się, w jaki sposób ów certyfikat ma być odnawiany. W opisanym przykładzie założeniem był reset sklepu dwa razy na dobę. Przygotowany w Bash skrypt wyłącza oraz usuwa aktywne kontenery, a następnie ponownie je uruchamia razem z kontenerem Certbota.
Jeśli produkcyjny deployment miałby być jednorazowy i aplikacja miałaby stale działać to jedyne co należałoby cyklicznie uruchamiać to kontener Certbota, a następnie przeładowanie konfiguracji Nginxa. Wszystko również byłoby wykonane za pomocą skryptu Bash dodanego do tablicy Crona.
Na pewno należy zwrócić uwagę by katalogi /var/www/html, /etc/letsencrypt i /var/lib/letsencrypt były podpięte w formie woluminów do kontenerów Certbota i Nginxa. Poza tym istotne jest zawarcie wszystkich parametrów automatyzujących akceptacje zgód etc. w poleceniu wykonywanym w command
.
Rezultat wdrożenia
To już wszystko. Można w przeglądarce wpisać domenę, pod którą uruchomiliśmy sklep i naszym oczom ukaże się domyślny layout z przykładowymi produktami:
A tak wygląda backoffice:
Całość wdrożona na czystej instalacji Ubuntu Server 20.04.3 LTS.
Autor
Piotr Bracha — pracuje jako administrator systemów. Karierę zaczynał jako młodszy administrator systemów w call center, gdzie miał możliwość poznania administrowania systemem CentOS i centralą telefoniczną Asterisk. Obecnie rozwija się w technologiach kontenerowych i chmurowych. Fan automatyzacji i porządku – w kodzie, ale też w środowisku pracy. Poza pracą uwielbia motoryzację i strzelectwo. Więcej artykułów autorstwa Piotra znajdziesz na Medium.