diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..053e3d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/app +/backup +/conf/docker-compose.override.yml +/conf/env/*.env +/conf/parameters.env +/volume diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..d258740 --- /dev/null +++ b/Makefile @@ -0,0 +1,183 @@ +PARAM = $(PWD)/conf/parameters.env +NOW = $(shell date +%Y%m%d"-"%H%M%S) + +$(shell ! test -e $(PARAM) && cp ./conf/parameters.dist.env ./conf/parameters.env) + +ifneq (,$(wildcard $(PARAM))) + include $(PARAM) +endif + +VAR_LIST = ENV CLIENT SRVNAME CACHE +__check_defined = $( \ + $(if $(value $1) \ + ,\ + ,$(error Variable '$1' est non définie ou vide))\ +) +$(foreach v, \ + $(VAR_LIST), \ + $(call __check_defined,$v) \ +) + +DOCKERCOMPOSE = $(shell command -v docker-compose 2> /dev/null) +USAGE = Usage: make ENV={prod|preprod|dev} {docker-build|docker-start|docker-stop|docker-restart} + +ifndef DOCKERCOMPOSE +$(error docker-compose is not available) +endif + +DC_OVERRIDE = $(shell test -e ./conf/docker-compose.override.yml && echo "--file ./conf/docker-compose.override.yml") + +DC_OVERRIDE_ENV = $(shell test -e ./conf/docker-compose.$(ENV).yml && echo "--file ./conf/docker-compose.$(ENV).yml") + +ifeq ($(CACHE), 1) +DC_PROFILE = --profile cache +endif + +DC = $(DOCKERCOMPOSE) --env-file ./conf/parameters.env --project-name "$(CLIENT)_$(ENV)" --file ./conf/docker-compose.yml $(DC_OVERRIDE) $(DC_OVERRIDE_ENV) $(DC_PROFILE) + +default: + $(info $(USAGE)) + $(error Exiting) + +docker-build: + $(DC) pull + $(DC) build + $(DC) up --force-recreate --detach + +docker-start: + $(DC) start + +docker-stop: + $(DC) stop + +docker-down: + $(DC) down --volumes --rmi local + +docker-restart: + $(DC) restart + +docker-rm: docker-stop + $(DC) rm + +docker-logs: + $(DC) logs --follow + +init-all: init-var-files + +init-var-files: + @echo " --> Init default parameters" + @cp conf/env/sample/mysql.env conf/env/mysql.env + @echo "!! Don't forget to edit env file in conf/env/*.env !!" + +config-all: config-nginx config-php config-db-root + +# - empty nginx default configuration file +# dont remove, file presence is tested on container start +# - change user nginx to user www-data +# - copy nginx app's configuration file +config-nginx: + @echo " --> Copying nginx configuration file" + @docker exec $(CLIENT).nginx.$(ENV) sh -c "echo > /etc/nginx/conf.d/default.conf" + @docker exec $(CLIENT).nginx.$(ENV) sed --in-place 's|user nginx|user www-data|g' /etc/nginx/nginx.conf + @docker cp ./conf/build/nginx/site.conf $(CLIENT).nginx.$(ENV):/etc/nginx/conf.d/ + @docker restart $(CLIENT).nginx.$(ENV) + +config-php: + @echo " --> Switching php ini file to $(ENV) mode" +ifeq ($(ENV), prod) + @docker exec $(CLIENT).php.$(ENV) ln -sf /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini +endif +ifeq ($(ENV), dev) + @docker exec $(CLIENT).php.$(ENV) ln -sf /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini +endif + @docker restart $(CLIENT).php.$(ENV) + +config-db-root: + @echo " --> Generating mysql auth file" + @cat conf/env/mysql.env \ + | python3 -c "import sys; import string; v=sys.stdin.readline().split('MYSQL_ROOT_PASSWORD=')[1]; print(string.Template(open('conf/build/mysql/my.cnf.tpl').read()).substitute({'PASSWORD':v}))" \ + | docker exec -i $(CLIENT).mysql.$(ENV) sh -c 'cat > /root/.my.cnf' + +db-backup: config-db-root + @echo " --> Backing up database" + @mkdir -p backup/ + @docker exec $(CLIENT).mysql.$(ENV) mysqldump -uroot database > backup/mysql_$(ENV)_$(NOW).sql + +db-restore: config-db-root + @echo " --> Restoring file to database (backup/mysql.sql)" + @docker exec -i $(CLIENT).mysql.$(ENV) mysql -uroot database < backup/mysql.sql + +presta-set-domain: config-db-root + @echo " --> Set domain URL for : " $(SRVNAME) + @echo "UPDATE ps_shop_url SET domain='$(SRVNAME)', domain_ssl='$(SRVNAME)';" \ + | docker exec -i $(CLIENT).mysql.$(ENV) mysql -uroot database + @echo "UPDATE ps_configuration SET value='$(SRVNAME)' WHERE name='PS_SHOP_DOMAIN' OR name='PS_SHOP_DOMAIN_SSL';" \ + | docker exec -i $(CLIENT).mysql.$(ENV) mysql -uroot database + +presta-enable-ssl: config-db-root + @echo " --> Enabling SSL" + @echo "UPDATE ps_configuration SET value=1 WHERE name='PS_SSL_ENABLED' OR name='PS_SSL_ENABLED_EVERYWHERE';" \ + | docker exec -i $(CLIENT).mysql.$(ENV) mysql -uroot database + +presta-disable-ssl: config-db-root + @echo " --> Disabling SSL" + @echo "UPDATE ps_configuration SET value=0 WHERE name='PS_SSL_ENABLED' OR name='PS_SSL_ENABLED_EVERYWHERE';" \ + | docker exec -i $(CLIENT).mysql.$(ENV) mysql -uroot database + +# https://devdocs.prestashop-project.org/8/development/architecture/file-structure/ +# https://devdocs.prestashop-project.org/8/contribute/contribute-pull-requests/contribute_using_localhost/#setting-up-file-rights +presta-enable-folder-security: + @echo " --> Enabling prestashop folder permissions" + @echo " chown" + @docker exec $(CLIENT).nginx.$(ENV) chown -R www-data:www-data /home/app/src + @echo " chmod files" + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src -type f -exec chmod 440 '{}' \; + @echo " chmod folders" + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src -type d -exec chmod 550 '{}' \; + @echo " make writable some folders" + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src/cache -type f -exec chmod 640 '{}' \; + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src/cache -type d -exec chmod 750 '{}' \; + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src/img -type f -exec chmod 640 '{}' \; + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src/img -type d -exec chmod 750 '{}' \; + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src/themes -type f -exec chmod 640 '{}' \; + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src/themes -type d -exec chmod 750 '{}' \; + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src/var -type f -exec chmod 640 '{}' \; + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src/var -type d -exec chmod 750 '{}' \; + +presta-disable-folder-security: + @echo " --> Disabling prestashop folder permissions" + @echo " chown" + @docker exec $(CLIENT).nginx.$(ENV) chown -R www-data:www-data /home/app/src + @echo " chmod files" + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src -type f -exec chmod 660 '{}' \; + @echo " chmod folders" + @docker exec $(CLIENT).nginx.$(ENV) find /home/app/src -type d -exec chmod 770 '{}' \; + +# https://devdocs.prestashop-project.org/8/basics/installation/advanced/install-from-cli/ +presta-install: + @echo " --> Installing Prestashop" + @echo " Launching install script" + @docker exec --user www-data --workdir /home/app/src/install/ --env-file ./conf/env/mysql.env $(CLIENT).php.$(ENV) \ + sh -c 'php -d error_reporting="E_ERROR" index_cli.php \ + --domain=$(SRVNAME) --ssl=0 --fixtures=0 --rewrite=1 --theme=classic \ + --language=fr --country=fr --timezone=Europe/Paris \ + --db_clear=1 --db_create=0 --db_server=mysql --db_name=$${MYSQL_DATABASE} --db_user=$${MYSQL_USER} --db_password=$${MYSQL_PASSWORD} \ + --firstname=Admin --lastname=E-DECLIC --email=contact@e-declic.com --password=edeclic56' + @echo " Deleting install folder" + @docker exec --user www-data $(CLIENT).php.$(ENV) rm -rf /home/app/src/install + +presta-config-admin-path: + @echo " --> Generating nginx conf for admin access" + $(eval admin_path = $(shell docker exec --user www-data $(CLIENT).php.$(ENV) sh -c 'basename $$(find /home/app/src/ -maxdepth 1 -type d -name "admin*")')) + @python3 -c "import string; print(string.Template(open('conf/build/nginx/admin.conf.tpl').read()).substitute({'ADMIN_PATH':'$(value admin_path)'}), end='')" \ + | docker exec -i $(CLIENT).php.$(ENV) sh -c 'cat > /home/app/conf/admin.conf' + @docker restart $(CLIENT).nginx.$(ENV) + @echo "- chemin d'accès à l'admin : /$(admin_path)/" >> app/README.md + @echo " Vous pouvez vous connecter à : " + @echo " http://$(SRVNAME)/$(admin_path)/" + +pull-app: + @echo " --> Pulling client's app" + git -C app/ pull + +.PHONY: default docker-build docker-start docker-stop docker-rm docker-down docker-logs init-all init-var-files config-all config-nginx config-php config-db-root db-backup db-restore presta-set-domain presta-enable-ssl presta-disable-ssl presta-enable-folder-security presta-disable-folder-security pull-app diff --git a/README.md b/README.md index e69de29..5686b91 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,2 @@ + +# Go to WikiJS 🤪 diff --git a/conf/build/nginx/admin.conf.tpl b/conf/build/nginx/admin.conf.tpl new file mode 100644 index 0000000..6424748 --- /dev/null +++ b/conf/build/nginx/admin.conf.tpl @@ -0,0 +1,5 @@ +location /$ADMIN_PATH/ { + if (!-e $$request_filename) { + rewrite ^ /$ADMIN_PATH/index.php last; + } +} diff --git a/conf/build/nginx/site.conf b/conf/build/nginx/site.conf new file mode 100644 index 0000000..3793ef5 --- /dev/null +++ b/conf/build/nginx/site.conf @@ -0,0 +1,115 @@ +# https://devdocs.prestashop-project.org/8/basics/installation/advanced/nginx/ + +upstream fastcgi_backend { + server php:9000; +} + +server { + + listen 80; + listen [::]:80; + + root /home/app/src; + index index.php; + + access_log /dev/stdout main; + error_log /dev/stderr; + + client_max_body_size 10M; + + # Redirect 404 errors to PrestaShop. + error_page 404 /index.php?controller=404; + + location = /favicon.ico { + log_not_found off; + access_log off; + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + # Images. + rewrite ^/(\d)(-[\w-]+)?/.+\.jpg$ /img/p/$1/$1$2.jpg last; + rewrite ^/(\d)(\d)(-[\w-]+)?/.+\.jpg$ /img/p/$1/$2/$1$2$3.jpg last; + rewrite ^/(\d)(\d)(\d)(-[\w-]+)?/.+\.jpg$ /img/p/$1/$2/$3/$1$2$3$4.jpg last; + rewrite ^/(\d)(\d)(\d)(\d)(-[\w-]+)?/.+\.jpg$ /img/p/$1/$2/$3/$4/$1$2$3$4$5.jpg last; + rewrite ^/(\d)(\d)(\d)(\d)(\d)(-[\w-]+)?/.+\.jpg$ /img/p/$1/$2/$3/$4/$5/$1$2$3$4$5$6.jpg last; + rewrite ^/(\d)(\d)(\d)(\d)(\d)(\d)(-[\w-]+)?/.+\.jpg$ /img/p/$1/$2/$3/$4/$5/$6/$1$2$3$4$5$6$7.jpg last; + rewrite ^/(\d)(\d)(\d)(\d)(\d)(\d)(\d)(-[\w-]+)?/.+\.jpg$ /img/p/$1/$2/$3/$4/$5/$6/$7/$1$2$3$4$5$6$7$8.jpg last; + rewrite ^/(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(-[\w-]+)?/.+\.jpg$ /img/p/$1/$2/$3/$4/$5/$6/$7/$8/$1$2$3$4$5$6$7$8$9.jpg last; + rewrite ^/c/([\w.-]+)/.+\.jpg$ /img/c/$1.jpg last; + + # AlphaImageLoader for IE and FancyBox. + rewrite ^images_ie/?([^/]+)\.(gif|jpe?g|png)$ js/jquery/plugins/fancybox/images/$1.$2 last; + + # Web service API. + rewrite ^/api/?(.*)$ /webservice/dispatcher.php?url=$1 last; + + # Installation sandbox. + rewrite ^(/install(?:-dev)?/sandbox)/.* /$1/test.php last; + + location / { + try_files $uri $uri/ /index.php$is_args$args; + } + + # .htaccess, .DS_Store, .htpasswd, etc. + location ~ /\. { + deny all; + } + + # Source code directories. + location ~ ^/(app|bin|cache|classes|config|controllers|docs|localization|override|src|tests|tools|translations|var|vendor)/ { + deny all; + } + + # vendor in modules directory. + location ~ ^/modules/.*/vendor/ { + deny all; + } + + # Prevent exposing other sensitive files. + location ~ \.(log|tpl|twig|sass|yml)$ { + deny all; + } + + # Prevent injection of PHP files. + location /img { + location ~ \.php$ { deny all; } + } + + location /upload { + location ~ \.php$ { deny all; } + } + + location ~ [^/]\.php(/|$) { + + # Split $uri to $fastcgi_script_name and $fastcgi_path_info. + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + + # Ensure that the requested PHP script exists before passing it + # to the PHP-FPM. + try_files $fastcgi_script_name =404; + + # Environment variables for PHP. + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $request_filename; + + fastcgi_index index.php; + + fastcgi_keep_conn on; + fastcgi_read_timeout 30s; + fastcgi_send_timeout 30s; + + # Uncomment these in case of long loading or 502/504 errors. + # fastcgi_buffer_size 256k; + # fastcgi_buffers 256 16k; + # fastcgi_busy_buffers_size 256k; + + fastcgi_pass fastcgi_backend; + } + + include "/home/app/conf/*.conf"; +} diff --git a/conf/build/php/Dockerfile b/conf/build/php/Dockerfile new file mode 100755 index 0000000..e743338 --- /dev/null +++ b/conf/build/php/Dockerfile @@ -0,0 +1,134 @@ +# https://hub.docker.com/_/php +# https://github.com/PrestaShop/docker/blob/master/base/images/7.4-fpm/Dockerfile +# https://devdocs.prestashop-project.org/1.7/basics/installation/system-requirements/ +# https://github.com/docker-library/php/blob/b9f17156020c3aef71df681b27684533529347a7/7.4/bullseye/fpm/Dockerfile + +FROM php:7.4-fpm + +RUN set -ex; \ + apt-get update; apt-get install -y \ + lsof \ + nano \ + less \ + git \ + locales \ + wget \ + unzip \ + ; \ + rm -rf /var/lib/apt/lists/ + +RUN set -ex; \ + echo 'fr_FR.UTF-8 UTF-8' > /etc/locale.gen; \ + /usr/sbin/locale-gen + +RUN set -ex; \ + apt-get update; apt-get install -y \ + libpcre3-dev \ + libonig-dev \ + libxml2-dev \ + libicu-dev \ + ghostscript \ + ; \ + rm -rf /var/lib/apt/lists/; \ + docker-php-source extract; \ + docker-php-ext-install iconv intl mbstring soap bcmath json; \ + docker-php-source delete; + +RUN set -ex; \ + docker-php-source extract; \ + if [ -d "/usr/src/php/ext/zip" ]; then \ + apt-get update; apt-get install -y \ + unzip \ + libzip-dev \ + ;\ + rm -rf /var/lib/apt/lists/; \ + docker-php-ext-install zip; \ + fi; \ + docker-php-source delete; + +RUN set -ex; \ + docker-php-source extract; \ + if [ -d "/usr/src/php/ext/imap" ]; then \ + apt-get update; apt-get install -y \ + libc-client-dev \ + libkrb5-dev \ + ;\ + rm -rf /var/lib/apt/lists/; \ + docker-php-ext-configure imap --with-imap-ssl --with-kerberos; \ + docker-php-ext-install imap; \ + fi; \ + docker-php-source delete; + +RUN set -ex; \ + docker-php-source extract; \ + if [ -d "/usr/src/php/ext/gd" ]; then \ + apt-get update; apt-get install -y \ + libpng-dev \ + libwebp-dev \ + libjpeg62-turbo-dev \ + libfreetype6-dev \ + libzip-dev \ + ; \ + rm -rf /var/lib/apt/lists/; \ + docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ --with-webp=/usr/include; \ + docker-php-ext-install gd; \ + fi; \ + docker-php-source delete; + +RUN set -ex; \ + docker-php-source extract; \ + if [ -d "/usr/src/php/ext/mcrypt" ]; then \ + apt-get update; apt-get install -y libmcrypt-dev; \ + rm -rf /var/lib/apt/lists/; \ + docker-php-ext-install mcrypt; \ + fi; \ + docker-php-source delete; + +RUN set -ex; \ + docker-php-source extract; \ + if [ -d "/usr/src/php/ext/mysqli" ]; then \ + apt-get update; apt-get install -y default-mysql-client; \ + rm -rf /var/lib/apt/lists/; \ + docker-php-ext-install mysqli; \ + fi; \ + docker-php-source delete; + +RUN set -ex; \ + docker-php-source extract; \ + if [ -d "/usr/src/php/ext/pdo_mysql" ]; then \ + apt-get update; apt-get install -y default-mysql-client; \ + rm -rf /var/lib/apt/lists/; \ + docker-php-ext-install pdo_mysql; \ + fi; \ + docker-php-source delete; + +RUN set -ex; \ + docker-php-source extract; \ + if [ -d "/usr/src/php/ext/opcache" ]; then \ + docker-php-ext-install opcache; \ + { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=60'; \ + echo 'opcache.fast_shutdown=1'; \ + echo 'opcache.enable_cli=1'; \ + } >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini; \ + fi; \ + docker-php-source delete; + +RUN set -ex; \ + apt-get update; apt-get install -y libmagickwand-dev; \ + rm -rf /var/lib/apt/lists/; \ + docker-php-source extract; \ + pecl install imagick-3.4.4; \ + docker-php-ext-enable imagick; \ + docker-php-source delete; + +RUN set -ex; \ + pecl install redis; + +RUN set -ex; \ + { \ + echo 'date.timezone = Europe/Paris'; \ + } > /usr/local/etc/php/conf.d/php_local.ini; diff --git a/conf/docker-compose.dev.yml b/conf/docker-compose.dev.yml new file mode 100755 index 0000000..85ba426 --- /dev/null +++ b/conf/docker-compose.dev.yml @@ -0,0 +1,23 @@ +version: '3' + +services: + + nginx: + ports: + - "80:80" + volumes: + - ../app:/home/app:cached + restart: "no" + + php: + volumes: + - ../app:/home/app:cached + restart: "no" + + mysql: + ports: + - "3306:3306" + restart: "no" + + redis: + restart: "no" diff --git a/conf/docker-compose.preprod.yml b/conf/docker-compose.preprod.yml new file mode 100755 index 0000000..4df1504 --- /dev/null +++ b/conf/docker-compose.preprod.yml @@ -0,0 +1,13 @@ +version: '3' + +services: + nginx: + networks: + - default + - frontweb_http_proxy + +networks: + default: + driver: bridge + frontweb_http_proxy: + external: true diff --git a/conf/docker-compose.prod.yml b/conf/docker-compose.prod.yml new file mode 100755 index 0000000..4df1504 --- /dev/null +++ b/conf/docker-compose.prod.yml @@ -0,0 +1,13 @@ +version: '3' + +services: + nginx: + networks: + - default + - frontweb_http_proxy + +networks: + default: + driver: bridge + frontweb_http_proxy: + external: true diff --git a/conf/docker-compose.yml b/conf/docker-compose.yml new file mode 100755 index 0000000..b06be22 --- /dev/null +++ b/conf/docker-compose.yml @@ -0,0 +1,44 @@ +version: '3' + +services: + + nginx: + image: nginx + container_name: ${CLIENT}.nginx.${ENV} + hostname: nginx + labels: + - traefik.enable=true + - traefik.port=80 + - traefik.docker.network=frontweb_http_proxy + - traefik.http.routers.${CLIENT}-${ENV}-secured.tls=true + - traefik.http.routers.${CLIENT}-${ENV}-secured.tls.certresolver=myhttpchallenge + - traefik.http.routers.${CLIENT}-${ENV}.rule=Host(`${SRVNAME}`) + - traefik.http.routers.${CLIENT}-${ENV}-secured.rule=Host(`${SRVNAME}`) + volumes: + - ../app:/home/app + restart: always + + php: + build: build/php + container_name: ${CLIENT}.php.${ENV} + hostname: php + volumes: + - ../app:/home/app + restart: always + + mysql: + image: mysql:5.6.40 + container_name: ${CLIENT}.mysql.${ENV} + hostname: mysql + env_file: env/mysql.env + volumes: + - ../volume/mysql/var.lib.mysql:/var/lib/mysql + restart: always + + redis: + image: redis + container_name: ${CLIENT}.redis.${ENV} + hostname: redis + profiles: + - cache + restart: always diff --git a/conf/env/sample/mysql.env b/conf/env/sample/mysql.env new file mode 100755 index 0000000..37c65e4 --- /dev/null +++ b/conf/env/sample/mysql.env @@ -0,0 +1,4 @@ +MYSQL_ROOT_PASSWORD=edcl56 +MYSQL_DATABASE=database +MYSQL_USER=user +MYSQL_PASSWORD=edcl56 \ No newline at end of file diff --git a/conf/parameters.dist.env b/conf/parameters.dist.env new file mode 100644 index 0000000..d0ca1c4 --- /dev/null +++ b/conf/parameters.dist.env @@ -0,0 +1,4 @@ +ENV=dev +CLIENT= +SRVNAME= +CACHE=0 \ No newline at end of file