A modern Docker LAMP stack and MEAN stack for local development

Last update: Jun 26, 2022

The Devilbox

Devilbox

Usage | Architecture | Community | Features | Intranet | Screenshots | Contributing | Logos | License

Devilbox

Release Gitter Discourse type License

Build Status Documentation Status Build Status Build Status Build Status Build Status Build Status


Support for valid https out of the box.

The Devilbox is a modern and highly customisable dockerized PHP stack supporting full LAMP and MEAN and running on all major platforms. The main goal is to easily switch and combine any version required for local development. It supports an unlimited number of projects for which vhosts, SSL certificates and DNS records are created automatically. Reverse proxies per project are supported to ensure listening server such as NodeJS can also be reached. Email catch-all and popular development tools will be at your service as well. Configuration is not necessary, as everything is already pre-setup.

Furthermore, the Devilbox provides an identical and reproducible development environment for different host operating systems.

Requirements

Linux OSX Windows Plus Docker

Architecture

Available Stacks

The Devilbox aims to be a swiss army knife for local development by providing you all the services you would ever need. To get an idea about the architecture behind it and to also see what's available have a look at the following diagrams and tables.

Smallest stack

This is the smallest possible and fully functional stack you can run

Full stack

To better understand what is actually possible have a look at the full example

Devilbox artwork

Available Container

The following table lists all integrated and pre-configured Docker container shipped by the Devilbox. Only the webserver and PHP container are mandatory, all others are optional and don't need to be started.

Each of them is also available in multiple different versions in order to reflect your exact desired environment.

Accel Web App SQL NoSQL Queue / Search ELK Utils
HAProxy Apache PHP MariaDB Memcached RabbitMQ ElasticSearch Bind
Varnish Nginx Python (Flask) MySQL MongoDB Solr Logstash Blackfire
PerconaDB Redis Kibana MailHog
PostgreSQL Ngrok

Documentation: Available Container

Community

The Devilbox has a lot of features reaching from a simple single-user development environment that works out of the box up to a shared development infrastructure for a corporate network.

In order to be aware about all that features, ensure to have skimmed over the documentation, so you know what can be done and how that might simplify your every-day life. If you ever run into any unforseen issues, feel free to join the chat or visit the forums and get community support quickly.

Documentation

Chat

Forum

Flames

devilbox.readthedocs.io gitter.im/devilbox devilbox.discourse.group github.com/devilbox/flames

Usage

Quick start

Linux and MacOS Windows
# Get the Devilbox
git clone https://github.com/cytopia/devilbox
# Create docker-compose environment file
cd devilbox
cp env-example .env
# Edit your configuration
vim .env
# Start all container
docker-compose up
1. Clone https://github.com/cytopia/devilbox to C:\devilbox with Git for Windows

2. Copy C:\devilbox\env-example to C:\devilbox\.env

3. Edit C:\devilbox\.env

4. Open a terminal on Windows and type:


# Start all container
C:\devilbox> docker-compose up

Documentation: Install the Devilbox | Start the Devilbox | .env file

Selective start

The above will start all containers, you can however also just start the containers you actually need. This is achieved by simply specifying them in the docker-compose command.

docker-compose up httpd php mysql redis

Documentation: Start only some container

Devilbox

Run different versions

Every single attachable container comes with many different versions. In order to select the desired version for a container, simply edit the .env file and uncomment the version of choice. Any combination is possible.

Apache Nginx PHP MySQL MariaDB Percona PgSQL Redis Memcached MongoDB
2.2 stable 5.2[1] 5.5 5.5 5.5 9.0 2.8 1.4 2.8
2.4 mainline 5.3 5.6 10.0 5.6 9.1 3.0 1.5 3.0
5.4 5.7 10.1 5.7 9.2 3.2 1.6 3.2
5.5 8.0 10.2 8.0 9.3 4.0 latest 3.4
5.6 10.3 9.4 5.0 3.6
7.0 10.4 9.5 6.0 4.0
7.1 10.5 9.6 latest 4.2
7.2 ... 4.4
7.3 12.3 latest
7.4 12.4
8.0[2] 13.0
8.1[2] latest

[1] PHP 5.2 is available to use, but it is not officially supported. The Devilbox intranet does not work with this version as PHP 5.2 does not support namespaces. Furthermore PHP 5.2 does only work with Apache 2.4, Nginx stable and Nginx mainline. It does not work with Apache 2.2. Use at your own risk.

[2] PHP 8.0 / PHP 8.1 are upcoming unreleased versions of PHP, which are directly built out of their official git branches every night to assure you will leverage their latest features.

Documentation: Change container versions

Additional services

Additionally to the default stack, there are a variety of other services that can be easily enabled and started.

Python (Flask) Blackfire ELK MailHog Ngrok RabbitMQ Solr HAProxy Varnish
2.7 1.8 5.x.y v1.0.0 2.x 3.6 5 1.x 4
... ... 6.x.y latest 3.7 6 5
3.7 1.18.0 7.x.y latest 7 6
3.8 latest latest latest

Documentation: Enable custom container

Enter the container

You can also work directly inside the php container. Simply use the bundled scripts shell.sh (or shell.bat for Windows). The PS1 will automatically be populated with current chosen php version. Navigate the the Devilbox directory and type the below listed command:

Linux and MacOS Windows
host> ./shell.sh
[email protected] in /shared/httpd $
C:\devilbox> shell.bat
[email protected] in /shared/httpd $

Your projects can be found in /shared/httpd. DNS records are automatically available inside the php container. Also every other service will be available on 127.0.0.1 inside the php container (tricky socat port-forwarding).

Documentation: Work inside the PHP container | Directory overview

Quick Video intro

Devilbox setup and workflow Devilbox email catch-all

Feature overview

The Devilbox has everything setup for you. The only thing you will have to install is Docker and Docker Compose. Virtual hosts and DNS entries will be created automatically, just by adding new project folders.

Documentation: Devilbox Prerequisites

Features

HTTPS support HTTPS is available by default for all projects and the bundled Intranet.
HTTP/2 support All HTTPS connections will offer HTTP/2 as the default protocol, except for Apache 2.2 which does not support it.
Auto virtual hosts New virtual hosts are created automatically and instantly whenever you add a project directory. This is done internally via vhost-gen and watcherd.
Automated SSL certs Valid SSL certificates for HTTPS are automatically created for each vhost and signed by the Devilbox CA.
Unlimited vhosts Run as many projects as you need with a single instance of the Devilbox.
Custom vhosts You can overwrite and customise the default applied vhost configuration for every single vhost.
Reverse proxy Have your NodeJS application served with a nice domain name and valid HTTPS.
Custom domains Choose whatever development domain you desire: *.loc, *.dev or use real domains as well: *.example.com
Auto DNS An integrated BIND server is able to create DNS entries automatically for your chosen domains.
Auto start scripts Custom startup scripts can be provided for all PHP container equally and also differently per PHP version to install custom software or automatically startup up your required tools.
Custom PHP config Overwrite any setting for PHP.
Custom PHP modules Load custom PHP modules on the fly.
Email catch-all All outgoing emails are catched and will be presented in the included intranet.
Self-validation Projects and configuration options are validated and marked in the intranet.
Xdebug Xdebug and a full blown PHP-FPM server is ready to serve.
Devilbox Flames Devilbox community plugins a.k.a. Devilbox Flames.
Many more See Documentation for all available features.

Documentation: Setup Auto DNS | Setup valid HTTPS | Configure Xdebug | Customize PHP

Batteries

The following batteries are available in the Devilbox intranet by default:

Adminer phpMyAdmin phpPgAdmin phpRedMin PHPMemcachedAdmin OpCacheGUI Mail viewer
Adminer phpMyAdmin phpPgAdmin phpRedMin PHPMemcached Admin OpCache GUI Mail viewer

Documentation: Devilbox Intranet

Tools

The following tools will assist you on creating new projects easily as well as helping you check your code against guidelines.

🔧 awesome-ci A set of tools for static code analysis:

file-cr, file-crlf, file-empty, file-nullbyte-char, file-trailing-newline, file-trailing-single-newline, file-trailing-space, file-utf8, file-utf8-bom, git-conflicts, git-ignored, inline-css, inline-js, regex-grep, regex-perl, syntax-bash, syntax-css, syntax-js, syntax-json, syntax-markdown, syntax-perl, syntax-php, syntax-python, syntax-ruby, syntax-scss, syntax-sh
🔧 git flow git-flow is a Git extensions to provide high-level repository operations for Vincent Driessen's branching model.
🔧 json lint jsonlint is a command line linter for JSON files.
🔧 laravel installer laravel is a command line tool that lets you easily install the Laravel framework.
🔧 linkcheck linkcheck is a command line tool that searches for URLs in files (optionally limited by extension) and validates their HTTP status code.
🔧 linuxbrew brew is a MacOS Homenbrew clone for Linux.
🔧 markdownlint markdownlint is a markdown linter.
🔧 mdl mdl is a markdown linter.
🔧 phalcon devtools phalcon is a command line tool that lets you easily install the PhalconPHP framework.
🔧 photon installer photon is a command line tool that lets you easily install the PhotonCMS.
🔧 php code sniffer phpcs is a command line tool that tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.
🔧 php code beautifier phpcbf is a command line tool that automatically correct coding standard violations.
🔧 php cs fixer php-cs-fixer is a tool to automatically fix PHP Coding Standards issues.
🔧 pm2 pm2 is Node.js Production Process Manager with a built-in Load Balancer.
🔧 stylelint stylelint is a css/scss linter.
🔧 symfony installer symfony is a command line tool that lets you easily install the Symfony framework.
🔧 tig tig is a text-mode interface for git.
🔧 wp-cli wp is a command line tool that lets you easily install WordPress.
🔧 yamllint yamllint is a linter for yaml files.

Well-known and popular tools will be at your service as well:

Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox

Documentation: Available Tools

Available PHP Modules

The Devilbox is a development stack, so it is made sure that a lot of PHP modules are available out of the box in order to work with many different frameworks.

  • Core enabled (cannot be disabled):
  • Enabled (can be disabled): 🗸
  • Available, but disabled (can be enabled): d
Modules PHP 5.2 PHP 5.3 PHP 5.4 PHP 5.5 PHP 5.6 PHP 7.0 PHP 7.1 PHP 7.2 PHP 7.3 PHP 7.4 PHP 8.0 PHP 8.1
amqp 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
apc 🗸 🗸 🗸 🗸
apcu 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
bcmath 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
blackfire d d d d d d d
bz2 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
calendar 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
Core
ctype
curl
date
dba 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
dom
enchant 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
ereg
exif 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
FFI 🗸
fileinfo 🗸
filter
ftp 🗸 🗸 🗸
gd 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
gettext 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
gmp 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
hash
iconv
igbinary 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
imagick 🗸 🗸 🗸 🗸 🗸 🗸 🗸
imap 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
interbase 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
intl 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
ioncube d d d d d d d d d d
json
ldap 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
libxml
mbstring 🗸 🗸
mcrypt 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
memcache 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
memcached 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
mhash
mongo 🗸 🗸 🗸 🗸 🗸
mongodb 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
msgpack 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
mysql 🗸 🗸 🗸
mysqli 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
mysqlnd
OAuth 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
oci8 d d d d d d d d d d d
openssl
pcntl 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
pcre
PDO
pdo_dblib 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
PDO_Firebird 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
pdo_mysql 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
PDO_OCI d d d d d d d
pdo_pgsql 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
pdo_sqlite
pdo_sqlsrv d d d d
pgsql 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
phalcon 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
Phar 🗸
posix
pspell 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
psr 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
rdkafka d d d d d d d d d
readline
recode 🗸 🗸 🗸 🗸 🗸 🗸 🗸
redis 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
Reflection
session
shmop 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
SimpleXML
snmp 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
soap 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
sockets 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
sodium
solr 🗸 🗸 🗸 🗸 🗸 🗸
SPL
SQLite
sqlite3
sqlsrv d d d d d
ssh2 🗸 🗸 🗸 🗸 🗸
standard
swoole d d d d d d d d d
sysvmsg 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
sysvsem 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
sysvshm 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
tidy 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
tokenizer
uploadprogress 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
vips 🗸 🗸 🗸 🗸 🗸
wddx 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
xdebug 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
xlswriter 🗸 🗸 🗸 🗸 🗸 🗸 🗸
xml
xmlreader
xmlrpc 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
xmlwriter
xsl 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
yaml 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
Zend OPcache 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
zip 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸 🗸
zlib
  • Core enabled (cannot be disabled):
  • Enabled (can be disabled): 🗸
  • Available, but disabled (can be enabled): d

PHP modules can be enabled or disabled on demand to reflect the state of your target environment.

Documentation: Enable/disable PHP modules

Custom PHP Modules

You can also copy any custom modules into mod/(php-fpm)-<VERSION> and add a custom *.ini file to load them.

Supported PHP Frameworks

As far as tested there are no limitations and you can use any Framework or CMS just as you would on your live environment. Below are a few examples of extensively tested Frameworks and CMS:

Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox Devilbox

Documentation:
Setup CakePHP | Setup CodeIgniter | Setup Contao | Setup CraftCMS | Setup Drupal | Setup Joomla | Setup Laravel | Setup Magento | Setup PhalconPHP | Setup PhotonCMS | Setup PrestaShop | Setup ProcessWire | Setup Shopware | Setup Symfony | Setup Typo3 | Setup WordPress | Setup Yii | Setup Zend

Supported reverse proxied applications

As far as tested there are no limitations and you can use any application that creates an open port. These ports will be reverse proxied by the web server and even allow you to use valid HTTPS for them. By the built-in autostart feature of the Devilbox you can ensure that your application automatically starts up as soon as you run docker-compose up.

NodeJS Python Flask Sphinx

Documentation:
Setup reverse proxy NodeJs | Setup reverse proxy Sphinx documentation

Intranet overview

The Devilbox comes with a pre-configured intranet on http://localhost and https://localhost. This can be explicitly disabled or password-protected. The intranet will not only show you, the chosen configuration, but also validate the status of the current configuration, such as if DNS records exists (on host and container), are directories properly set-up. Additionally it provides external tools to let you interact with databases and emails.

Documentation: Devilbox Intranet

Screenshots

A few examples of how the built-in intranet looks like.

Contributing Open Source Helpers

The Devilbox is still a young project with a long roadmap of features to come. Features are decided by you - the community, so any kind of contribution is welcome.

To increase visibility and bug-free operation:

  • Star this project
  • Open up issues for bugs and feature requests
  • Clone this project and submit fixes or features
  • Visit the Devilbox Community Forums for announcements and to help others

Additionally you can subscribe to Devilbox on CodeTriage, read up on CONTRIBUTING.md and check the ROADMAP about what is already planned for the near future.

Logos

Logos and banners can be found at devilbox/artwork. Feel free to use or modify them by the terms of their license.

License

MIT License

Copyright (c) 2016 cytopia

GitHub

https://github.com/cytopia/devilbox
Comments
  • 1. MongoDB not starting

    Hi,

    I am using the windows 10 pro and i have recently installed the docker the latest version.

    I wanted to use devilbox services everything is working fine but the mongodb and postgre database.

    I am getting the below mention error while looking into the mongo logs.

    E:\Docker\devilbox (master)
    λ docker-compose logs mongo
    Attaching to devilbox_mongo_1
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=4b8802b75a60
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten] db version v3.4.10
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten] git version: 078f28920cb24de0dd479b5ea6c66c644f6326e9
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten] OpenSSL version: OpenSSL 1.0.1t  3 May 2016
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten] allocator: tcmalloc
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten] modules: none
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten] build environment:
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten]     distmod: debian81
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten]     distarch: x86_64
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten]     target_arch: x86_64
    mongo_1  | 2017-12-05T15:07:52.781+0000 I CONTROL  [initandlisten] options: {}
    mongo_1  | 2017-12-05T15:07:52.788+0000 I STORAGE  [initandlisten] wiredtiger_open config: create,cache_size=478M,session_max=20000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),
    mongo_1  | 2017-12-05T15:07:52.954+0000 E STORAGE  [initandlisten] WiredTiger error (17) [1512486472:954333][1:0x7f1585c39d40], connection: /data/db/WiredTiger.wt: handle-open: open: File exists
    mongo_1  | 2017-12-05T15:07:52.956+0000 I STORAGE  [initandlisten] WiredTiger message unexpected file WiredTiger.wt found, renamed to WiredTiger.wt.11
    mongo_1  | 2017-12-05T15:07:52.958+0000 E STORAGE  [initandlisten] WiredTiger error (1) [1512486472:958291][1:0x7f1585c39d40], connection: /data/db/WiredTiger.wt: handle-open: open: Operation not permitted
    mongo_1  | 2017-12-05T15:07:52.960+0000 I -        [initandlisten] Assertion: 28595:1: Operation not permitted src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp 276
    mongo_1  | 2017-12-05T15:07:52.962+0000 I STORAGE  [initandlisten] exception in initAndListen: 28595 1: Operation not permitted, terminating
    mongo_1  | 2017-12-05T15:07:52.963+0000 I NETWORK  [initandlisten] shutdown: going to close listening sockets...
    mongo_1  | 2017-12-05T15:07:52.963+0000 I NETWORK  [initandlisten] removing socket file: /tmp/mongodb-27017.sock
    mongo_1  | 2017-12-05T15:07:52.963+0000 I NETWORK  [initandlisten] shutdown: going to flush diaglog...
    mongo_1  | 2017-12-05T15:07:52.963+0000 I CONTROL  [initandlisten] now exiting
    mongo_1  | 2017-12-05T15:07:52.963+0000 I CONTROL  [initandlisten] shutting down with code:100
    

    I dont understand this error and so i decided to ask you for help. Please guide me if there anything i need to change.

    Thank you very much

    Reviewed by aadi-khan at 2017-12-05 15:30
  • 2. Auto-DNS not working properly

    Hi,

    I have pulled today latest image and all works well except auto-dns feature. Under php 7.1, apache 2.4, Docker version 17.09.0-ce, build afdb6d4 and osx high sierra when I set nameserver 127.0.0.1 in resolv.conf, flush the dns cache, delete the container and run compose up virtualhosts are not properly resolved. If I place them in hosts file all works well. Any suggestions for further debugging? I left DEBUG_COMPOSE_ENTRYPOINT=1 and checked the log but everything seems fine, no errors on the screen so far.

    Also after wifi reconnect on osx of dns are changed and file completely wiped, so this means that I have to add localhost on each wifi reconnect...

    Reviewed by rslid at 2017-10-03 20:51
  • 3. Blackfire integration seems incomplete?

    ISSUE TYPE

    • Question

    SUMMARY

    Support for Blackfire seems to be incomplete. After adding Blackfire through the instructions, the profiling returns an error "Probe not found, invalid signature".

    It seems like Blackfire PHP is not being installed? If I install it - along with the agent - manually, nothing works either.

    Are there any of these steps which are missing in the configuration, so Blackfire starts correctly when issuing "docker-compose up"?

    • https://blackfire.io/docs/integrations/docker
    • https://blackfire.io/docs/up-and-running/installation
    • https://blackfire.io/docs/book/06-installation

    Goal

    To be able to run Blackfire profiling on my local Devilbox Docker environment.

    Thank you in advance.

    Reviewed by runedalton at 2019-01-01 18:41
  • 4. 403 forbidden after update

    after update (from git & containers incl. removing and recreating images) from 0.13 to 0.14 I get an 403 on all hosts (including localhost). also ssl cert is not correct set up now (security page). Can anyone confirm or a hand for debugging?

    • [ x] Pull latest dockers (e.g.: docker pull cytopia/<used_docker>) before running docker-compose up done that

    • [ x] Specify used docker versions (php, web and database) php 7.0, 7.1, 7.1 database mariadb-10.1 apache 2.2 2.4

    • [ x] Attach logs for php, mysql and webserver (found in log/ directory) the log files did not update. this is the compose up output

    • [x ] Start with debug mode and attach docker-compose output (.env setting DEBUG_COMPOSE_ENTRYPOINT=1) logs.txt

    • [x ] Never use different mysql|mariadb versions on the same HOST_PATH_MYSQL_DATADIR on existing database files. Different mysql|mariadb versions might upgrade/corrupt existing database files. If you have done that already, start with a different path of HOST_PATH_MYSQL_DATADIR (to an empty directory) and try again.

    Please also specify the following info:

    • [x ] Which operating system are you at (Linux, OSX or Windows) windows 10
    • [x ] docker version docker ce Version 18.03.1-ce-win65 (17513)
    • [x ] docker-compose version 1.21.1
    Reviewed by chrizz1001 at 2018-06-07 13:19
  • 5. DNS problem (docker-toolbox \ Win7x64 \ non-admin user)

    Hi, I've already complete setup & using devilbox tool on OS X (it means that i understand how it works fine)

    But on Windows7 x64 host i have a following issue. Accordingly to documentation, we need to specify a "LOCAL_LISTEN_ADDR", which is 127.0.0.1 by default. Docker tools software versions provided in attachment image. In case of windows 7 we can use only docker-toolbox, and cannot use a docker-native client... While it starts - it shows an IP 192.168.99.100 which must replace a default IP address (127.0.0.1:) from .env file.

    Once I've set that - i'm launching the utility... Starting procedure are the same as on OS X... The tool sequentially launches a few web services and goes to idle state...

    Afterwards my browser (Google chrome Version 60.0.3112.113 (Official Build) (64-bit)) can't get to the main web-panel, neither one of following addresses are recognized by DNS 127.0.0.1 192.168.99.100 172.16.238.11 localhost

    I've tries to set all of them to "LOCAL_LISTEN_ADDR" value, each time after any changes being made I've erase all present containers through following commands: docker rm -f $(docker ps -a -q) docker rmi $(docker images -q) for now it is still doesn't see web-panel...

    Who is sharp enough, please advise - what it can be? Is there any solution for that? Thanks for paying attention, good luck

    Software versions are dockers ip

    Working idle state of devilbox tool idle-state

    localhost 127001 19216899100 1721623811

    Reviewed by John-MEO-o at 2017-08-29 21:30
  • 6. How to add subdomains?

    Hi,

    I'm sorry, I'm not sure how can I use devilbox along with WP multisite? To be more precise, I would like to use subdomains. So, maybe this is the main question - how to add subdomains ? Thanks!

    Reviewed by mrpsiho at 2017-11-08 17:35
  • 7. Xdebug can't connect on Docker for Mac

    If you encounter a bug and something does not work, make sure you have done the following and check those boxes before submitting an issue - thank you!

    • [x] Pull latest dockers (e.g.: docker pull cytopia/<used_docker>) before running docker-compose up
    • [x] Specify used docker versions (php, web and database)
    • [ ] Attach logs for php, mysql and webserver (found in log/ directory)
    • [ ] Start with debug mode and attach docker-compose output (.env setting DEBUG_COMPOSE_ENTRYPOINT=1)
    • [ ] Never use different mysql|mariadb versions on the same HOST_PATH_MYSQL_DATADIR on existing database files. Different mysql|mariadb versions might upgrade/corrupt existing database files. If you have done that already, start with a different path of HOST_PATH_MYSQL_DATADIR (to an empty directory) and try again.

    Please also specify the following info:

    • [x] Which operating system are you at (Linux, OSX or Windows)

    macOS Sierra 0.12.6

    • [x] docker version
    Docker version 18.03.1-ce, build 9ee9f40
    
    • [x] docker-compose version
    docker-compose version 1.21.0, build 5920eb0
    docker-py version: 3.2.1
    CPython version: 3.6.4
    OpenSSL version: OpenSSL 1.0.2o  27 Mar 2018
    

    xdebug.log

    xdebug.remote_enable=on
    xdebug.remote_host=host.docker.internal
    xdebug.remote_connect_back=0
    xdebug.idekey=code
    xdebug.remote_log=/var/log/php/xdebug.log
    

    I'm using vscode with the following configuration

    {
        // Use IntelliSense to learn about possible attributes.
        // Hover to view descriptions of existing attributes.
        // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [
    
            {
                "name": "Listen for XDebug",
                "type": "php",
                "request": "launch",
                "port": 9000,
                "stopOnEntry": true,
                "log": true,
                "pathMappings": {
                    "/shared/httpd/test/htdocs": "${workspaceFolder}"
                }
            }
        ]
    }
    
    Reviewed by jmcbee at 2018-05-06 18:15
  • 8. 504 Gateway timeout errors

    Hi - I'm getting 504 timeout errors and general performance issues, especially when trying to access wp-admin across various sites within auto DNS. Any ideas? I'm on:

    OSX High Sierra Docker Version 18.03.0-ce-mac60 (23751) Compose: 1.20.1

    Here's my .env attached env.txt

    Reviewed by stefanlesik at 2018-04-25 16:03
  • 9. Customized Nginx Conf hasn't applied

    Note: This issue have been resolved. While creating custom configuration based on templates don't use "\t" (TAB) characters on yml files. They will cause you some trouble :)

    Original Issue:

    Hello,

    I'm using Devilbox on Linux: Latest release, latest docker and latest docker-compose version.

    I am using PHP 7.1, Nginx-Stable versions.

    I've created .devilbox inside my project folder and put nginx.yml

    And I put fastcgi_read_timeout 300; parameter.

    But I get timeout while working on a PHP project.

    So I've go inside the docker shell and check httpd settings.

    I've checked /etc/httpd/vhost.d/myproject.conf file and the fastcgi_read_timeout settings it nowhere.

    So maybe I'm doing something wrong or maybe there is a bug.

    What do you think?

    Reviewed by alivelimeli at 2017-11-15 15:57
  • 10. please provide Setup Instructions (an Install Guide) in the docs for Ghost - Headless CMS

    Reviewed by BobbyBabes at 2020-05-06 16:17
  • 11. Working on NodeJS project - use nginx as reverse proxy / upstream Node app

    Hi! Hope you are doing well. I have a question about using devilbox while working on NodeJS project. In essence, I would like to ask how to access my Node app via custom domain like 'node-app.loc'?

    I start my Node app inside a container via terminal and it is up and running on localhost:3000. But I am lost how to access it? Visiting http://node-app.loc gives me Error 403 Forbidden. I guess I could achieve what I need by modifying nginx.yml within '.devilbox' folder of my project folder, however, I don't know what exactly to put inside this config file. Please, help.

    Reviewed by mrpsiho at 2018-05-01 09:47
  • 12. [Bug]: xDebug session cause db aborting connection after 3 minutes.

    Have you already looked into this bug?

    • [X] I have checked the Troubleshooting Guide
    • [X] I have checked Release notes for potential migration steps
    • [X] I have checked existing issues for similar bugs
    • [X] I have googled this bug already with no luck
    • [ ] I have not done any of the above

    (Optional) Error message

    devilbox-mysql-1 | 2022-06-22 13:08:51 512 [Warning] Aborted connection 512 to db: 'some_db' user: 'root' host: '172.16.238.10' (Got an error reading communication packets)

    What went wrong?

    When using xDebug session is dropped after about 3 minutes. I tried raising every possible timeout and wait configuration on php, nginx, mariadb with no luck. Am I missing something is there anything else I could set to prevent connection DB drop?

    In Browser this results in 502 Bad Gateway.

    Expected behaviour

    My XDebug session should not be dropped.

    How can we reproduce the bug?

    1. Start debug session.
    2. Hit any breakpoint.
    3. Wait 3 minutes.

    Host Operating System

    Windows

    Host Platform (amd64, arm64, other)

    amd64

    (Linux only) Is SELinux enabled?

    I don't know

    Docker version

    20.10.14, build a224086

    Docker Compose version

    v2.2.3

    Devilbox version

    v2.2.0

    Have you removed stopped containers before starting?

    Yes

    Have you pulled latest Docker images before starting?

    Yes

    Devilbox start command

    docker-compose up httpd php mysql bind

    Config: .env file

    ###
    ###  ---------------------------------------------------
    ###  D E V I L B O X   R U N - T I M E   S E T T I N G S
    ###  ---------------------------------------------------
    ###
    ###  All the following settings are applied during
    ###  $ docker-compose up
    ###
    ###  No need to rebuild any docker images!
    ###
    ###  IMPORTANT:
    ###  ----------
    ###  When changing any values ensure to stop, rm and restart:
    ###  $ docker-compose stop
    ###  $ docker-compose rm -f
    ###  $ docker-compose up
    ###
    ###  NOTE:
    ###  -----
    ###  For you own custom variables, scroll to the bottom
    ###
    
    # The following line will disable any shellcheck warnings throughout this file
    # shellcheck disable=SC2034,SC2125
    
    
    ###
    ### Show all executed commands in each
    ### docker image during docker-compose up?
    ###
    ### 0: Quiet
    ### 1: Verbose
    ### 2: More verbose
    DEBUG_COMPOSE_ENTRYPOINT=2
    
    
    ###
    ### Log to file or Docker logs.
    ###
    ### Logging to file means log files are available under log/
    ### on your host operating system.
    ### Logging to Docker logs means log files are streamed to
    ### stdout and stderr.
    ###
    ### 1: Log to Docker logs
    ### 0: Log to file
    ###
    DOCKER_LOGS=0
    
    
    ###
    ### Relative or absolute path to the devilbox repository.
    ### (Used as a prefix for all mount paths)
    ### There is no need to change this.
    ###
    ### The only exception is for OSX users wanting to use NFS
    ### mounts instead of Filesystem mounts due to degraded performance
    ### on OSX.
    ###
    ### Note: When changing this variable you must re-create the container.
    ###       Simply remove it, it will be auto-created during the next start:
    ###
    ### $ docker-compose rm -f
    ###
    DEVILBOX_PATH=.
    
    
    ###
    ### At what IP address should the docker services listen
    ### on the Host computer?
    ###
    ### The specified default should be fine for Linux and OSX (127.0.0.1:).
    ### If you are on windows, you will probably have to change
    ### it to the IP address of the docker machine.
    ###
    ### a.) Leave blank, to listen on all interfaces (no trailing colon ':')
    ###    LOCAL_LISTEN_ADDR=
    ### b.) If an IP is specified, note the trailing colon ':'
    ###    LOCAL_LISTEN_ADDR=127.0.0.1:
    ###
    LOCAL_LISTEN_ADDR=
    
    
    ###
    ### This is the domain suffix your projects will be made available
    ### with mass-virtual-hosting.
    ### It is also required for the internal DNS server to be setup.
    ###
    ### Note: Only ALPHA ([a-zA-Z]+) characters are supported.
    ###
    ### Example:
    ###   TLD_SUFFIX=loc
    ### Makes your project available under xxxx.loc
    ###
    ### Example:
    ###   TLD_SUFFIX=local
    ### Makes your project available under xxxx.local
    ###
    TLD_SUFFIX=loc
    
    
    ###
    ### Optional DNS configuration
    ### Allows you to add extra DNS records (above the wildcard entry)
    ### Useful if your host computer run other Docker services that you want to connect to or reach
    ### from within the Devilbox network by a custom hostname.
    ###
    ### Format:
    ### -------
    ### Resolve any custom defined hostname to an IP address (useable inside container and host os)
    ###     EXTRA_HOSTS=<hostname>=<ip>[,<hostname>=<ip>]
    ###
    ### Resolve any custom defined hostname to whatever IP address a CNAME resolves to
    ### (Useable inside the container and host OS).
    ### Note: CNAME must be resolvable by Google DNS
    ###     EXTRA_HOSTS=<hostname>=<CNAME>[,<hostname>=<CNAME>]
    ###
    ### Examples:
    ### ---------
    ### EXTRA_HOSTS=hostname.loc=1.2.3.4
    ### EXTRA_HOSTS=host.loc=1.2.3.4,host.example.org=3.4.5.6
    EXTRA_HOSTS=
    
    
    ###
    ### Set your user id and group id
    ###
    ### This should be changed to the value of your local
    ### users uid and gid
    ###
    ### Type `id` on the terminal to find out your values
    ###
    NEW_UID=1000
    NEW_GID=999
    
    
    ###
    ### Timezone for PHP Docker container (system and php.ini)
    ###
    TIMEZONE=UTC
    
    
    
    ################################################################################
    ###
    ### INTRANET SETTINGS
    ###
    ################################################################################
    
    ###
    ### TLD_SUFFIX domains are checked if they are set in the
    ### host computer /etc/hosts or available via attached DNS server.
    ### Timeout is done on vhosts.php (intranet) via ajax calls.
    ### In order to keep performance, set this to a low value.
    ### DNS checks might not succeed in time on slow machines.
    ### If DNS is valid, but timeout is expired, set this to a higher value.
    ###
    ### DNS_CHECK_TIMEOUT value is how many seconds to time out
    ### Default is to timeout after 1 second (DNS_CHECK_TIMEOUT=1)
    ###
    DNS_CHECK_TIMEOUT=1
    
    
    ###
    ### Devilbox UI SSL Certificate generation
    ###
    ### When using SSL each certificate requires names for which it is responsible:
    ### Common Name as well as alternative names.
    ###
    ### Specify comma separated hostnames below by which you want to access the Devilbox.
    ### Those hostnames will be included in the SSL certificate for the Devilbox intranet.
    ### This has nothing to do for SSL certificates for projects, it is just for the intranet
    ### itself.
    ###
    DEVILBOX_UI_SSL_CN=localhost,*.localhost,devilbox,*.devilbox,httpd
    
    
    ###
    ### Devilbox UI Password protection enable/disable (1/0)
    ###
    ### Set DEVILBOX_UI_PROTECT to 1 in order to password protect the
    ### intranet.
    ###
    ### Example:
    ###   DEVILBOX_UI_PROTECT=1
    ###   DEVILBOX_UI_PROTECT=0
    ###
    DEVILBOX_UI_PROTECT=0
    
    
    ###
    ### Devilbox UI Password
    ###
    ### When DEVILBOX_UI_PROTECT=1, use the following password
    ### to log in. The password can always be changed.
    ### When changing the password, make sure to restart your
    ### PHP container.
    ###
    ### Example:
    ###   DEVILBOX_UI_PASSWORD=my-very-secure-password
    ###   DEVILBOX_UI_PASSWORD=Some pass with spaces
    ###
    ### The default username is 'devilbox'
    ###
    DEVILBOX_UI_PASSWORD=password
    
    
    ###
    ### Enable the Devilbox Intranet?
    ###
    ### Example:
    ###   DEVILBOX_UI_ENABLE=1
    ###   DEVILBOX_UI_ENABLE=0
    ###
    DEVILBOX_UI_ENABLE=1
    
    
    ###
    ### Automatically be logged in into phpMyAdmin
    ###
    ### Example:
    ###   DEVILBOX_VENDOR_PHPMYADMIN_AUTOLOGIN=1
    ###   DEVILBOX_VENDOR_PHPMYADMIN_AUTOLOGIN=0
    ###
    DEVILBOX_VENDOR_PHPMYADMIN_AUTOLOGIN=1
    
    
    ###
    ### Automatically be logged in into phpPgAdmin
    ###
    ### Example:
    ###   DEVILBOX_VENDOR_PHPPGADMIN_AUTOLOGIN=1
    ###   DEVILBOX_VENDOR_PHPPGADMIN_AUTOLOGIN=0
    ###
    DEVILBOX_VENDOR_PHPPGADMIN_AUTOLOGIN=1
    
    
    
    ################################################################################
    ###
    ### 1. Choose Images (Version)
    ###
    ################################################################################
    
    ###
    ### You can choose any combination of httpd, mysql, postgresql or php.
    ### Each of them are fully compatible between one another.
    ###
    
    
    ###
    ### 1.1 Choose PHP Server Image
    ###
    ### Note: PHP 5.2 is not officially supported. Intranet won't work (due to lack of namespace support).
    ###       PHP 5.2 only works with Apache 2.4, Nginx stable and Nginx mainline.
    ###       Use at your own risk.
    ###
    #PHP_SERVER=5.2
    #PHP_SERVER=5.3
    #PHP_SERVER=5.4
    #PHP_SERVER=5.5
    #PHP_SERVER=5.6
    #PHP_SERVER=7.0
    #PHP_SERVER=7.1
    #PHP_SERVER=7.2
    #PHP_SERVER=7.3
    #PHP_SERVER=7.4
    #PHP_SERVER=8.0
    #PHP_SERVER=8.1
    PHP_SERVER=8.2
    
    
    ###
    ### 1.2 Choose HTTPD Server Image
    ###
    #HTTPD_SERVER=apache-2.2
    #HTTPD_SERVER=apache-2.4
    HTTPD_SERVER=nginx-stable
    #HTTPD_SERVER=nginx-mainline
    
    
    ###
    ### 1.3 Choose MySQL Server Image
    ###
    #MYSQL_SERVER=mysql-5.5
    #MYSQL_SERVER=mysql-5.6
    #MYSQL_SERVER=mysql-5.7
    #MYSQL_SERVER=mysql-8.0
    #MYSQL_SERVER=mariadb-5.5
    #MYSQL_SERVER=mariadb-10.0
    #MYSQL_SERVER=mariadb-10.1
    #MYSQL_SERVER=mariadb-10.2
    #MYSQL_SERVER=mariadb-10.3
    #MYSQL_SERVER=mariadb-10.4
    MYSQL_SERVER=mariadb-10.5
    #MYSQL_SERVER=mariadb-10.6
    # MYSQL_SERVER=mariadb-10.7
    #MYSQL_SERVER=percona-5.5
    #MYSQL_SERVER=percona-5.6
    #MYSQL_SERVER=percona-5.7
    #MYSQL_SERVER=percona-8.0
    
    
    ###
    ### 1.4 Choose PostgreSQL Server Image
    ###
    ### IMPORTANT: Alpine based images might cause issues on Docker Toolbox or OSX
    ###            https://github.com/docker/toolbox/issues/510
    ###
    #PGSQL_SERVER=9.0
    #PGSQL_SERVER=9.1
    #PGSQL_SERVER=9.2
    #PGSQL_SERVER=9.2-alpine
    #PGSQL_SERVER=9.3
    #PGSQL_SERVER=9.3-alpine
    #PGSQL_SERVER=9.4
    #PGSQL_SERVER=9.4-alpine
    #PGSQL_SERVER=9.5
    #PGSQL_SERVER=9.5-alpine
    #PGSQL_SERVER=9.6
    #PGSQL_SERVER=9.6-alpine
    #PGSQL_SERVER=10.0
    #PGSQL_SERVER=10.0-alpine
    #PGSQL_SERVER=10.1
    #PGSQL_SERVER=10.1-alpine
    #PGSQL_SERVER=10.2
    #PGSQL_SERVER=10.2-alpine
    #PGSQL_SERVER=10.3
    #PGSQL_SERVER=10.3-alpine
    #PGSQL_SERVER=10.4
    #PGSQL_SERVER=10.4-alpine
    #PGSQL_SERVER=10.5
    #PGSQL_SERVER=10.5-alpine
    #PGSQL_SERVER=10.6
    #PGSQL_SERVER=10.6-alpine
    #PGSQL_SERVER=10.7
    #PGSQL_SERVER=10.7-alpine
    #PGSQL_SERVER=10.8
    #PGSQL_SERVER=10.8-alpine
    #PGSQL_SERVER=10.9
    #PGSQL_SERVER=10.9-alpine
    #PGSQL_SERVER=10.10
    #PGSQL_SERVER=10.10-alpine
    #PGSQL_SERVER=10.11
    #PGSQL_SERVER=10.11-alpine
    #PGSQL_SERVER=11.0
    #PGSQL_SERVER=11.0-alpine
    #PGSQL_SERVER=11.1
    #PGSQL_SERVER=11.1-alpine
    #PGSQL_SERVER=11.2
    #PGSQL_SERVER=11.2-alpine
    #PGSQL_SERVER=11.3
    #PGSQL_SERVER=11.3-alpine
    #PGSQL_SERVER=11.4
    #PGSQL_SERVER=11.4-alpine
    #PGSQL_SERVER=11.5
    #PGSQL_SERVER=11.5-alpine
    #PGSQL_SERVER=11.6
    #PGSQL_SERVER=11.6-alpine
    #PGSQL_SERVER=11.7
    #PGSQL_SERVER=11.7-alpine
    #PGSQL_SERVER=11.8
    #PGSQL_SERVER=11.8-alpine
    #PGSQL_SERVER=11.9
    #PGSQL_SERVER=11.9-alpine
    #PGSQL_SERVER=12.0
    #PGSQL_SERVER=12.0-alpine
    #PGSQL_SERVER=12.1
    #PGSQL_SERVER=12.1-alpine
    #PGSQL_SERVER=12.2
    #PGSQL_SERVER=12.2-alpine
    #PGSQL_SERVER=12.3
    #PGSQL_SERVER=12.3-alpine
    # PGSQL_SERVER=12.4
    #PGSQL_SERVER=12.4-alpine
    # PGSQL_SERVER=13.0
    #PGSQL_SERVER=13.0-alpine
    PGSQL_SERVER=latest
    #PGSQL_SERVER=alpine
    
    
    ###
    ### 1.5 Choose Redis Server Image
    ###
    ### IMPORTANT: Alpine based images might cause issues on Docker Toolbox or OSX
    ###            https://github.com/docker/toolbox/issues/510
    ###
    #REDIS_SERVER=2.8
    #REDIS_SERVER=3.0
    #REDIS_SERVER=3.0-alpine
    #REDIS_SERVER=3.2
    #REDIS_SERVER=3.2-alpine
    #REDIS_SERVER=4.0
    #REDIS_SERVER=4.0-alpine
    #REDIS_SERVER=5.0
    #REDIS_SERVER=5.0-alpine
    REDIS_SERVER=6.0
    #REDIS_SERVER=6.0-alpine
    #REDIS_SERVER=latest
    #REDIS_SERVER=alpine
    
    
    ###
    ### 1.6 Choose Memcached Server Image
    ###
    ### IMPORTANT: Alpine based images might cause issues on Docker Toolbox or OSX
    ###            https://github.com/docker/toolbox/issues/510
    ###
    #MEMCD_SERVER=1.4
    #MEMCD_SERVER=1.4-alpine
    #MEMCD_SERVER=1.5
    #MEMCD_SERVER=1.5-alpine
    MEMCD_SERVER=1.6
    #MEMCD_SERVER=1.6-alpine
    #MEMCD_SERVER=latest
    #MEMCD_SERVER=alpine
    
    
    ###
    ### 1.7 Choose Mongo Server Image
    ###
    #MONGO_SERVER=2.8
    #MONGO_SERVER=3.0
    #MONGO_SERVER=3.2
    #MONGO_SERVER=3.4
    #MONGO_SERVER=3.6
    #MONGO_SERVER=4.0
    #MONGO_SERVER=4.2
    MONGO_SERVER=4.4
    #MONGO_SERVER=latest
    
    
    
    ################################################################################
    ###
    ### 2. Host Mounts (Your computer)
    ###
    ################################################################################
    
    ###
    ### Global mount options
    ###
    ### Note: When adding custom mount options, ensure to start with a
    ###       leading ',' (comma), as those options are prepended to already
    ###       existing mount options.
    ###
    ### Note: If no mount options are specified, leave this variable empty
    ###       and do not add a leading ',' (comma).
    ###
    ### MOUNT_OPTIONS=,cached
    ### MOUNT_OPTIONS=
    ###
    ### Example: Allow to share mounts accross container with SELINUX enabled
    ###
    ### MOUNT_OPTIONS=,z
    ###
    MOUNT_OPTIONS=
    
    
    ###
    ### Local filesystem path to www projects.
    ###
    ### Note: When changing this variable you must re-create the container.
    ###       Simply remove it, it will be auto-created during the next start:
    ###
    ### $ docker-compose rm -f
    ###
    HOST_PATH_HTTPD_DATADIR=./data/www
    
    
    ###
    ### Local filesystem path to where your backups are stored
    ###
    ### Note: When changing this variable you must re-create the container.
    ###       Simply remove it, it will be auto-created during the next start:
    ###
    ### $ docker-compose rm -f
    ###
    HOST_PATH_BACKUPDIR=./backups
    
    
    ###
    ### The path on your host OS of the ssh directory to be mounted into the
    ### PHP container into /home/devilbox/.ssh.
    ###
    ### IMPORTANT: The path is mounted read-only to ensure you cannot accidentally
    ##             delete anything inside the php container.
    ###
    HOST_PATH_SSH_DIR=~/.ssh
    
    
    
    ################################################################################
    ###
    ### 3. PHP Docker Settings
    ###
    ################################################################################
    
    ###
    ### Enable certain PHP modules which are not enabled by default
    ###
    ### Currently the only modules that can be enabled are 'ioncube' and 'blackfire'
    ### Also ensure to disable xdebug when using any of the above:
    ### https://xdebug.org/docs/install#compat
    ###
    ### PHP_MODULES_ENABLE=ioncube, blackfire
    ###
    PHP_MODULES_ENABLE=
    
    
    ###
    ### Disable any PHP modules that you don't require
    ###
    ### Specify a comma separated list without spaces of modules to disable
    ###
    ### PHP_MODULES_DISABLE=xdebug,imagick,swoole
    ###
    PHP_MODULES_DISABLE=oci8,PDO_OCI,pdo_sqlsrv,sqlsrv,rdkafka,swoole
    
    
    ###
    ### Postfix settings for email catch-all
    ###
    ### When set to '1' postfix is normally started and made available. However you still need
    ### to configure it to your needs yourself. For that you can use the autostart scripts
    ### and define a couple of 'postconf -e name=value' commands.
    ###
    ### When set to '2' (email catch-all), no mail will leave the Devilbox. It is automatically
    ### internally routed the the devilbox mail account and you can see each sent mail
    ### in the bundled intranet: https://localhost/mail.php
    ###
    ### Values:
    ### 0: Disable postfix (do not start it)
    ### 1: Enable/Start postfix
    ### 2: Enable/Start postfix and enable email catch-all
    ###
    PHP_MAIL_CATCH_ALL=2
    
    
    ###
    ### Configure everything else about PHP in
    ### * cfg/php-ini-X.X/*.ini
    ### * cfg/php-fpm-X.X/*.conf
    
    
    
    ################################################################################
    ###
    ### 4. HTTPD Docker Settings
    ###
    ################################################################################
    
    ###
    ### Expose HTTPD Port to Host
    ###
    HOST_PORT_HTTPD=80
    HOST_PORT_HTTPD_SSL=443
    
    
    ###
    ### SSL (HTTP/HTTPS) settings for automated vhost generation
    ###
    ### By default each project will have two vhosts (one for HTTP and one for HTTPS).
    ### You can control the SSL settings for your projects via the below stated values.
    ###
    ### This is internally achieved via the '-m' argument of https://github.com/devilbox/vhost-gen
    ###
    ### Values:
    ###   * both:  Serve HTTP and HTTPS for all projects
    ###   * redir: HTTP always redirects to HTTPS
    ###   * ssl:   Only serve HTTPS
    ###   * plain: Only serve HTTP
    ###
    HTTPD_VHOST_SSL_TYPE=both
    
    
    ###
    ### Document Root Subdirectory
    ###
    ### In your project directory, which subfolder should
    ### serve your files?
    ###
    ### When changing this value, restart the devilbox.
    ###
    HTTPD_DOCROOT_DIR=htdocs
    
    
    ###
    ### Per vHost Config Subdirectory
    ###
    ### In your project directory, which subfolder should
    ### hold apache, nginx templates for a customized vhost?
    ###
    ### When changing this value, restart the devilbox.
    ###
    HTTPD_TEMPLATE_DIR=.devilbox
    
    
    ###
    ### Webserver timeout (in seconds) to upstream PHP-FPM server
    ###
    ### This value should be greater than PHP's max_execution_time,
    ### otherwise the php script could still run and the webserver will
    ### simply drop the connection before getting an answer by PHP.
    ###
    HTTPD_TIMEOUT_TO_PHP_FPM=86400
    
    
    ###
    ### NGINX ONLY
    ###
    ### Set worker_processes and worker_connections
    ###
    ### https://nginx.org/en/docs/ngx_core_module.html#worker_processes
    ### https://nginx.org/en/docs/ngx_core_module.html#worker_connections
    ###
    HTTPD_NGINX_WORKER_PROCESSES=auto
    HTTPD_NGINX_WORKER_CONNECTIONS=1024
    
    
    
    ################################################################################
    ###
    ### 5. MySQL Docker Settings
    ###
    ################################################################################
    
    ###
    ### MySQL root user password
    ###
    ### The password is required for the initial creation of the MySQL database
    ### as well as the Devilbox intranet to display schema and configuration settings.
    ###
    ### If you change your MySQL root user password via mysql cli, phpMyAdmin or other tools
    ### after the database has been created, ensure to adjust the value here accordingly as well.
    ###
    ### If you only change this value here after the database has been created,
    ### the MySQL root user password will not actually be changed and the Devilbox intranet
    ### won't be able to connect to the MySQL service.
    ###
    MYSQL_ROOT_PASSWORD=
    
    
    ###
    ### Expose MySQL Port to Host
    ###
    HOST_PORT_MYSQL=3306
    
    
    
    ################################################################################
    ###
    ### 6. PostgreSQL Docker Settings
    ###
    ################################################################################
    
    ###
    ### PostgreSQL 'root' user name (usually postgres)
    ###
    PGSQL_ROOT_USER=postgres
    
    
    ###
    ### PostgreSQL 'root' user password
    ###
    ### If you want to set a password, ensure to remove 'trust' from
    ### PGSQL_HOST_AUTH_METHOD below
    ###
    PGSQL_ROOT_PASSWORD=
    
    
    ###
    ### In order to not use a password for PostgreSQL, keep this value at 'trust'
    ###
    PGSQL_HOST_AUTH_METHOD=trust
    
    
    ###
    ### Expose PostgreSQL Port to Host
    ###
    HOST_PORT_PGSQL=5432
    
    
    
    ################################################################################
    ###
    ### 7. Redis Docker Settings
    ###
    ################################################################################
    
    ###
    ### Expose Redis Port to Host
    ###
    HOST_PORT_REDIS=6379
    
    
    ###
    ### Custom startup arguments
    ###
    ### Apply custom startup arguments to redis
    ###
    ### Example: Password protection
    ###   Add password protection to the Redis server by specifying it should
    ###   require a password.
    ###   Note: Do not add quotes or spaces to the password
    ###
    ###   REDIS_ARGS=--requirepass my-redis-root-password
    ###
    ### Example: Verbosity
    ###
    ###   REDIS_ARGS=--loglevel verbose
    ###
    REDIS_ARGS=
    #REDIS_ARGS=--loglevel verbose --requirepass my-redis-root-password
    
    
    
    ################################################################################
    ###
    ### 8. Memcached Docker Settings
    ###
    ################################################################################
    
    ###
    ### Expose Memcached Port to Host
    ###
    HOST_PORT_MEMCD=11211
    
    
    
    ################################################################################
    ###
    ### 9. MongoDB Docker Settings
    ###
    ################################################################################
    
    ###
    ### Expose MongoDB Port to Host
    ###
    HOST_PORT_MONGO=27017
    
    
    
    ################################################################################
    ###
    ### 10. Bind Docker Settings
    ###
    ################################################################################
    
    ###
    ### Expose Bind Port to Host
    ###
    HOST_PORT_BIND=1053
    
    
    ###
    ### Add comma separated DNS server from which you want to receive DNS
    ### You can also add DNS servers from your LAN (if any are available)
    ###
    BIND_DNS_RESOLVER=8.8.8.8,8.8.4.4
    
    
    ###
    ### Validate DNSSEC
    ###
    ### Values:
    ###  no:    DNSSEC validation is disabled
    ###  yes:   DNSSEC validation is enabled, but a trust anchor must be manually configured.
    ###  auto:  DNSSEC validation is enabled, and a default trust anchor for root zone is used.
    ###
    BIND_DNSSEC_VALIDATE=no
    
    
    ###
    ### Bind timing options (time in seconds)
    ###
    ### Leave empty for defaults.
    ### Only change when you know what you are doing.
    ###
    BIND_TTL_TIME=
    BIND_REFRESH_TIME=
    BIND_RETRY_TIME=
    BIND_EXPIRY_TIME=
    BIND_MAX_CACHE_TIME=
    
    
    ###
    ### Show DNS Queries in Docker logs output?
    ###
    ### 1: Yes
    ### 0: No
    BIND_LOG_DNS_QUERIES=0
    
    
    
    ################################################################################
    ###
    ### 11. Custom variables
    ###
    ################################################################################
    
    ###
    ### Any variable defined in this file will be available
    ### as environment variables to your PHP/HHV Docker container.
    ###
    ### This might be useful to set application environment and retrieve
    ### them via: <?php getenv('MY_APPLICATION_ENV'); ?>
    ###
    
    
    ###
    ### Example:
    ### <?php echo getenv('Foo'); ?> would produce: 'some value'
    ###
    #Foo=some value
    

    Config: docker-compose.override.yml

    version: '2.3'
    services:
      php:
        extra_hosts:
          docker.for.wsl2.host.internal: ${IP}
    

    Config: ./check-config.sh

    #!/usr/bin/env bash
    
    set -e
    set -u
    set -o pipefail
    
    
    #--------------------------------------------------------------------------------------------------
    # GLOBALS
    #--------------------------------------------------------------------------------------------------
    RET_CODE=0
    MY_UID="$( id -u )"
    MY_GID="$( id -g )"
    DEBUG=0
    
    
    #--------------------------------------------------------------------------------------------------
    # Functions
    #--------------------------------------------------------------------------------------------------
    
    ###
    ### Logger functions
    ###
    log_err() {
    	>&2 printf "\\e[1;31m[ERR]   %s\\e[0m\\n" "${1}"
    }
    
    log_note() {
    	>&2 printf "\\e[1;33m[NOTE]  %s\\e[0m\\n" "${1}"
    }
    
    log_info() {
    	printf "\\e[;34m[INFO]  %s\\e[0m\\n" "${1}"
    }
    
    log_ok() {
    	printf "\\e[;32m[SUCC]  %s\\e[0m\\n" "${1}"
    }
    log_debug() {
    	if [ "${DEBUG}" -eq "1" ]; then
    		printf "[DEBUG] %s\\n" "${1}"
    	fi
    }
    
    ###
    ### Output functions
    ###
    print_head_1() {
    	printf "\\n# "
    	printf "%0.s=" {1..78}
    	printf "\\n"
    
    	printf "# %s\\n" "${1}"
    
    	printf "# "
    	printf "%0.s=" {1..78}
    	printf "\\n"
    }
    
    ###
    ### File functions
    ###
    file_get_uid() {
    	if [ "$(uname)" = "Linux" ]; then
    		stat --format '%u' "${1}"
    	else
    		stat -f '%u' "${1}"
    	fi
    }
    
    file_get_gid() {
    	if [ "$(uname)" = "Linux" ]; then
    		stat --format '%g' "${1}"
    	else
    		stat -f '%g' "${1}"
    	fi
    }
    
    # Returns 4-digit format
    file_get_perm() {
    	local perm
    	local len
    
    	if [ "$(uname)" = "Linux" ]; then
    		# If no special permissions are set (no sticky bit...), linux will
    		# only output the 3 digit number
    		perm="$( stat --format '%a' "${1}" )"
    	else
    		perm="$( stat -f '%OLp' "${1}" )"
    	fi
    
    	# For special cases check the length and add a leading 0
    	len="$(echo "${perm}" | awk '{ print length() }')"
    	if [ "${len}" = "3" ]; then
    		perm="0${perm}"
    	fi
    
    	echo "${perm}"
    }
    
    # Get path with '~' replace with correct home path
    get_path() {
    	echo "${1/#\~/${HOME}}"
    }
    
    # Returns sub directories by one level
    # Also returns symlinks if they point to a directory
    get_sub_dirs_level_1() {
    	local dir="${1}"
    	dir="${dir#./}"   # Remove leading './' if it exists
    	dir="${dir%/}"    # Remove trailing '/' if it exists
    	# shellcheck disable=SC2016
    	find "${dir}" \
    		| grep -Ev "^${dir}\$" \
    		| grep -Ev "^${dir}/.+/" \
    		| xargs -n1 sh -c 'if [ -d "${1}" ]; then echo "${1}"; fi'  -- \
    		| sort
    }
    
    # Returns sub directories by two level
    # Also returns symlinks if they point to a directory
    get_sub_dirs_level_2() {
    	local dir="${1}"
    	dir="${dir#./}"   # Remove leading './' if it exists
    	dir="${dir%/}"    # Remove trailing '/' if it exists
    	# shellcheck disable=SC2016
    	find "${dir}" \
    		| grep -Ev "^${dir}\$" \
    		| grep -Ev "^${dir}/.+/.+/" \
    		| xargs -n1 sh -c 'if [ -d "${1}" ]; then echo "${1}"; fi'  -- \
    		| sort
    }
    
    # Returns the value of .env var
    get_env_value() {
    	local val
    	val="$( grep -E "^${1}=" .env )"
    	echo "${val#*=}"
    }
    
    # Validate a DNS record
    validate_dns() {
    	ping -c1 "${1}" >/dev/null 2>&1
    }
    
    
    
    #--------------------------------------------------------------------------------------------------
    # Check git
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking git"
    
    GIT_STATUS="$( git status -s )"
    if [ -z "${GIT_STATUS}" ]; then
    	log_ok "git is clean"
    else
    	log_err "git is unclean"
    	echo "${GIT_STATUS}"
    	RET_CODE=$(( RET_CODE + 1))
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Check env file
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking .env file"
    
    if [ -f .env ]; then
    	log_ok ".env file exists"
    else
    	log_err ".env file does not exist"
    	RET_CODE=$(( RET_CODE + 1))
    	exit 1
    fi
    if [ -r .env ]; then
    	log_ok ".env file is readable"
    else
    	log_err ".env file is not readable"
    	RET_CODE=$(( RET_CODE + 1))
    	exit 1
    fi
    
    # Ensure all variables exist in .env file
    ENV_VAR_MISSING=0
    while read -r env_var; do
    	if ! grep -E "^${env_var}=" .env >/dev/null; then
    		log_err "Variable '${env_var}' missing in .env file"
    		RET_CODE=$(( RET_CODE + 1))
    		ENV_VAR_MISSING=1
    	else
    		log_debug "Variable '${env_var}' is present in '.env file"
    	fi
    done < <(grep -E '^[A-Z].+=' env-example  | awk -F'=' '{print $1}')
    if [ "${ENV_VAR_MISSING}" = "0" ]; then
    	log_ok "All variables are present in .env file"
    fi
    
    # Ensure variables are not duplicated in .env
    ENV_VAR_DUPLICATED=0
    while read -r env_var; do
    	OCCURANCES="$( grep -Ec "^${env_var}=" .env )"
    	if [ "${OCCURANCES}" != "1" ]; then
    		log_err "Variable '${env_var}' should only be defined once. Occurances: ${OCCURANCES}"
    		RET_CODE=$(( RET_CODE + 1))
    		ENV_VAR_DUPLICATED=1
    	else
    		log_debug "Variable '${env_var}' is defined exactly once."
    	fi
    done < <(grep -E '^[A-Z].+=' env-example  | awk -F'=' '{print $1}')
    if [ "${ENV_VAR_DUPLICATED}" = "0" ]; then
    	log_ok "No variables is duplicated in .env file"
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Check env file values
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking .env file values"
    
    WRONG_ENV_FILES_VALUES=0
    
    DEBUG_COMPOSE_ENTRYPOINT="$( get_env_value "DEBUG_COMPOSE_ENTRYPOINT" )"
    if [ "${DEBUG_COMPOSE_ENTRYPOINT}" != "0" ] && [ "${DEBUG_COMPOSE_ENTRYPOINT}" != "1" ] && [ "${DEBUG_COMPOSE_ENTRYPOINT}" != "2" ]; then
    	log_err "Variable 'DEBUG_COMPOSE_ENTRYPOINT' should be 0, 1 or 2. Has: ${DEBUG_COMPOSE_ENTRYPOINT}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'DEBUG_COMPOSE_ENTRYPOINT' has correct value: ${DEBUG_COMPOSE_ENTRYPOINT}"
    fi
    
    DOCKER_LOGS="$( get_env_value "DOCKER_LOGS" )"
    if [ "${DOCKER_LOGS}" != "0" ] && [ "${DOCKER_LOGS}" != "1" ]; then
    	log_err "Variable 'DOCKER_LOGS' should be 0 or 1. Has: ${DOCKER_LOGS}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'DOCKER_LOGS' has correct value: ${DOCKER_LOGS}"
    fi
    
    DEVILBOX_PATH="$( get_env_value "DEVILBOX_PATH" )"
    if [ ! -d "${DEVILBOX_PATH}" ]; then
    	log_err "Variable 'DEVILBOX_PATH' directory does not exist: ${DEVILBOX_PATH}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'DEVILBOX_PATH' directory exists: ${DEVILBOX_PATH}"
    fi
    
    DEVILBOX_PATH_PERM="$( file_get_perm "${DEVILBOX_PATH}" )"
    if [ "${DEVILBOX_PATH_PERM}" != "0755" ] && [ "${DEVILBOX_PATH_PERM}" != "0775" ] && [ "${DEVILBOX_PATH_PERM}" != "0777" ]; then
    	log_err "Variable 'DEVILBOX_PATH' directory must be 0755, 0775 or 0777. Has: ${DEVILBOX_PATH_PERM}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'DEVILBOX_PATH' directory has correct permissions: ${DEVILBOX_PATH_PERM}"
    fi
    
    DEVILBOX_PATH_PERM="$( file_get_uid "${DEVILBOX_PATH}" )"
    if [ "${DEVILBOX_PATH_PERM}" != "${MY_UID}" ]; then
    	log_err "Variable 'DEVILBOX_PATH' directory uid must be ${MY_UID}. Has: ${DEVILBOX_PATH_PERM}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'DEVILBOX_PATH' diretory has correct uid: ${DEVILBOX_PATH_PERM}"
    fi
    
    DEVILBOX_PATH_PERM="$( file_get_gid "${DEVILBOX_PATH}" )"
    if [ "${DEVILBOX_PATH_PERM}" != "${MY_GID}" ]; then
    	log_err "Variable 'DEVILBOX_PATH' directory gid must be ${MY_GID}. Has: ${DEVILBOX_PATH_PERM}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'DEVILBOX_PATH' diretory has correct gid: ${DEVILBOX_PATH_PERM}"
    fi
    
    LOCAL_LISTEN_ADDR="$( get_env_value "LOCAL_LISTEN_ADDR" )"
    if [ -n "${LOCAL_LISTEN_ADDR}" ]; then
    	if ! echo "${LOCAL_LISTEN_ADDR}" | grep -E ':$' >/dev/null; then
    		log_err "Variable 'LOCAL_LISTEN_ADDR' is not empty and missing trailing ':'"
    		RET_CODE=$(( RET_CODE + 1))
    		WRONG_ENV_FILES_VALUES=1
    	elif ! echo "${LOCAL_LISTEN_ADDR}" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:$' >/dev/null; then
    		log_err "Variable 'LOCAL_LISTEN_ADDR' has wrong value: '${LOCAL_LISTEN_ADDR}'"
    		RET_CODE=$(( RET_CODE + 1))
    		WRONG_ENV_FILES_VALUES=1
    	else
    		log_debug "Variable 'LOCAL_LISTEN_ADDR' has correct value: ${LOCAL_LISTEN_ADDR}"
    	fi
    else
    	log_debug "Variable 'LOCAL_LISTEN_ADDR' has correct value: ${LOCAL_LISTEN_ADDR}"
    fi
    
    HOST_PATH_HTTPD_DATADIR="$( get_path "$( get_env_value "HOST_PATH_HTTPD_DATADIR" )" )"
    if [ ! -d "${HOST_PATH_HTTPD_DATADIR}" ]; then
    	log_err "Variable 'HOST_PATH_HTTPD_DATADIR' directory does not exist: ${HOST_PATH_HTTPD_DATADIR}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'HOST_PATH_HTTPD_DATADIR' directory exists: ${HOST_PATH_HTTPD_DATADIR}"
    fi
    
    HOST_PATH_HTTPD_DATADIR_PERM="$( file_get_perm "${HOST_PATH_HTTPD_DATADIR}" )"
    if [ "${HOST_PATH_HTTPD_DATADIR_PERM}" != "0755" ] && [ "${HOST_PATH_HTTPD_DATADIR_PERM}" != "0775" ] && [ "${HOST_PATH_HTTPD_DATADIR_PERM}" != "0777" ]; then
    	log_err "Variable 'HOST_PATH_HTTPD_DATADIR' directory must be 0755, 0775 or 0777. Has: ${HOST_PATH_HTTPD_DATADIR_PERM}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'HOST_PATH_HTTPD_DATADIR' directory has correct permissions: ${HOST_PATH_HTTPD_DATADIR_PERM}"
    fi
    
    HOST_PATH_HTTPD_DATADIR_PERM="$( file_get_uid "${HOST_PATH_HTTPD_DATADIR}" )"
    if [ "${HOST_PATH_HTTPD_DATADIR_PERM}" != "${MY_UID}" ]; then
    	log_err "Variable 'HOST_PATH_HTTPD_DATADIR' directory uid must be ${MY_UID}. Has: ${HOST_PATH_HTTPD_DATADIR_PERM}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'HOST_PATH_HTTPD_DATADIR' directory has correct uid: ${HOST_PATH_HTTPD_DATADIR_PERM}"
    fi
    
    HOST_PATH_HTTPD_DATADIR_PERM="$( file_get_gid "${HOST_PATH_HTTPD_DATADIR}" )"
    if [ "${HOST_PATH_HTTPD_DATADIR_PERM}" != "${MY_GID}" ]; then
    	log_err "Variable 'HOST_PATH_HTTPD_DATADIR' directory gid must be ${MY_GID}. Has: ${HOST_PATH_HTTPD_DATADIR_PERM}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'HOST_PATH_HTTPD_DATADIR' directory has correct gid: ${HOST_PATH_HTTPD_DATADIR_PERM}"
    fi
    
    PHP_SERVER="$( get_env_value "PHP_SERVER" )"
    if ! grep -E "^#?PHP_SERVER=${PHP_SERVER}\$" env-example >/dev/null; then
    	log_err "Variable 'PHP_SERVER' has wrong value: ${PHP_SERVER}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'PHP_SERVER' has correct value: ${PHP_SERVER}"
    fi
    
    HTTPD_SERVER="$( get_env_value "HTTPD_SERVER" )"
    if ! grep -E "^#?HTTPD_SERVER=${HTTPD_SERVER}\$" env-example >/dev/null; then
    	log_err "Variable 'HTTPD_SERVER' has wrong value: ${HTTPD_SERVER}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'HTTPD_SERVER' has correct value: ${HTTPD_SERVER}"
    fi
    
    MYSQL_SERVER="$( get_env_value "MYSQL_SERVER" )"
    if ! grep -E "^#?MYSQL_SERVER=${MYSQL_SERVER}\$" env-example >/dev/null; then
    	log_err "Variable 'MYSQL_SERVER' has wrong value: ${MYSQL_SERVER}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'MYSQL_SERVER' has correct value: ${MYSQL_SERVER}"
    fi
    
    PGSQL_SERVER="$( get_env_value "PGSQL_SERVER" )"
    if ! grep -E "^#?PGSQL_SERVER=${PGSQL_SERVER}\$" env-example >/dev/null; then
    	log_err "Variable 'PGSQL_SERVER' has wrong value: ${PGSQL_SERVER}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'PGSQL_SERVER' has correct value: ${PGSQL_SERVER}"
    fi
    
    REDIS_SERVER="$( get_env_value "REDIS_SERVER" )"
    if ! grep -E "^#?REDIS_SERVER=${REDIS_SERVER}\$" env-example >/dev/null; then
    	log_err "Variable 'REDIS_SERVER' has wrong value: ${REDIS_SERVER}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'REDIS_SERVER' has correct value: ${REDIS_SERVER}"
    fi
    
    MEMCD_SERVER="$( get_env_value "MEMCD_SERVER" )"
    if ! grep -E "^#?MEMCD_SERVER=${MEMCD_SERVER}\$" env-example >/dev/null; then
    	log_err "Variable 'MEMCD_SERVER' has wrong value: ${MEMCD_SERVER}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'MEMCD_SERVER' has correct value: ${MEMCD_SERVER}"
    fi
    
    MONGO_SERVER="$( get_env_value "MONGO_SERVER" )"
    if ! grep -E "^#?MONGO_SERVER=${MONGO_SERVER}\$" env-example >/dev/null; then
    	log_err "Variable 'MONGO_SERVER' has wrong value: ${MONGO_SERVER}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'MONGO_SERVER' has correct value: ${MONGO_SERVER}"
    fi
    
    NEW_UID="$( get_env_value "NEW_UID" )"
    if [ "${NEW_UID}" != "${MY_UID}" ]; then
    	log_err "Variable 'NEW_UID' has wrong value: '${NEW_UID}'. Should have: ${MY_UID}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'NEW_UID' has correct value: '${NEW_UID}'"
    fi
    
    NEW_GID="$( get_env_value "NEW_GID" )"
    if [ "${NEW_GID}" != "${MY_GID}" ]; then
    	log_err "Variable 'NEW_GID' has wrong value: '${NEW_GID}'. Should have: ${MY_GID}"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'NEW_GID' has correct value: '${NEW_GID}'"
    fi
    
    TLD_SUFFIX="$( get_env_value "TLD_SUFFIX" )"
    TLD_SUFFIX_BLACKLIST="dev|com|org|net|int|edu|de"
    if echo "${TLD_SUFFIX}" | grep -E "^(${TLD_SUFFIX_BLACKLIST})\$" >/dev/null; then
    	log_err "Variable 'TLD_SUFFX' should not be set to '${TLD_SUFFIX}'. It is a real tld domain."
    	log_err "All DNS requests will be intercepted to this tld domain and re-routed to the HTTP container."
    	log_info "Consider using a subdomain value of e.g.: 'mydev.${TLD_SUFFIX}' instead."
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    elif [ "${TLD_SUFFIX}" = "localhost" ]; then
    	log_err "Variable 'TLD_SUFFX' should not be set to '${TLD_SUFFIX}'. It is a loopback address."
    	log_info "See: https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06"
    	RET_CODE=$(( RET_CODE + 1))
    	WRONG_ENV_FILES_VALUES=1
    else
    	log_debug "Variable 'TLD_SUFFIX' has correct value: '${TLD_SUFFIX}'"
    fi
    
    if [ "${WRONG_ENV_FILES_VALUES}" = "0" ]; then
    	log_ok "All .env file variables have correct values"
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Ensure cfg/, mod/ and log/ directories exist
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking required Devilbox core directories exist"
    
    # /cfg/php-fpm-VERSION
    DIR_MISSING=0
    while read -r php_version; do
    	if [ ! -d "cfg/php-fpm-${php_version}" ]; then
    		log_err "Directory 'cfg/php-fpm-${php_version}' is missing"
    		RET_CODE=$(( RET_CODE + 1))
    		DIR_MISSING=1
    	else
    		log_debug "Directory 'cfg/php-fpm-${php_version}' is present"
    	fi
    done < <(grep -E '^#?PHP_SERVER=' env-example  | awk -F'=' '{print $2}')
    if [ "${DIR_MISSING}" = "0" ]; then
    	log_ok "All PHP cfg/ sub directories are present"
    fi
    
    # /log/php-fpm-VERSION
    DIR_MISSING=0
    while read -r php_version; do
    	if [ ! -d "log/php-fpm-${php_version}" ]; then
    		log_err "Directory 'log/php-fpm-${php_version}' is missing"
    		RET_CODE=$(( RET_CODE + 1))
    		DIR_MISSING=1
    	else
    		log_debug "Directory 'log/php-fpm-${php_version}' is present"
    	fi
    done < <(grep -E '^#?PHP_SERVER=' env-example  | awk -F'=' '{print $2}')
    if [ "${DIR_MISSING}" = "0" ]; then
    	log_ok "All PHP log/ sub directories are present"
    fi
    
    # /mod/php-fpm-VERSION
    DIR_MISSING=0
    while read -r php_version; do
    	if [ ! -d "mod/php-fpm-${php_version}" ]; then
    		log_err "Directory 'mod/php-fpm-${php_version}' is missing"
    		RET_CODE=$(( RET_CODE + 1))
    		DIR_MISSING=1
    	else
    		log_debug "Directory 'mod/php-fpm-${php_version}' is present"
    	fi
    done < <(grep -E '^#?PHP_SERVER=' env-example  | awk -F'=' '{print $2}')
    if [ "${DIR_MISSING}" = "0" ]; then
    	log_ok "All PHP mod/ sub directories are present"
    fi
    
    # /cfg/apache|nginx-VERSION
    DIR_MISSING=0
    while read -r httpd_version; do
    	if [ ! -d "cfg/${httpd_version}" ]; then
    		log_err "Directory 'cfg/${httpd_version}' is missing"
    		RET_CODE=$(( RET_CODE + 1))
    		DIR_MISSING=1
    	else
    		log_debug "Directory 'cfg/${httpd_version}' is present"
    	fi
    done < <(grep -E '^#?HTTPD_SERVER=' env-example  | awk -F'=' '{print $2}')
    if [ "${DIR_MISSING}" = "0" ]; then
    	log_ok "All HTTPD cfg/ sub directories are present"
    fi
    
    # /log/apache|nginx-VERSION
    DIR_MISSING=0
    while read -r httpd_version; do
    	if [ ! -d "log/${httpd_version}" ]; then
    		log_err "Directory 'log/${httpd_version}' is missing"
    		RET_CODE=$(( RET_CODE + 1))
    		DIR_MISSING=1
    	else
    		log_debug "Directory 'log/${httpd_version}' is present"
    	fi
    done < <(grep -E '^#?HTTPD_SERVER=' env-example  | awk -F'=' '{print $2}')
    if [ "${DIR_MISSING}" = "0" ]; then
    	log_ok "All HTTPD log/ sub directories are present"
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Devilbox Directory permissions
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking devilbox core directory permissions"
    
    DEVILBOX_DIRS=(
    	"autostart"
    	"bash"
    	"ca"
    	"cfg"
    	"compose"
    	"log"
    	"mod"
    	"supervisor"
    )
    
    # Check allowed directory permissions: 0755 0775 0777
    DEVILBOX_DIR_PERM_WRONG=0
    for search_dir in "${DEVILBOX_DIRS[@]}"; do
    	while read -r my_dir; do
    		PERM="$( file_get_perm "${my_dir}" )"
    		if [ "${PERM}" != "0755" ] && [ "${PERM}" != "0775" ] && [ "${PERM}" != "0777" ]; then
    			log_err "Directory '${my_dir}' should have 0755, 0775 or 0777 permissions. Has: ${PERM} permissions"
    			RET_CODE=$(( RET_CODE + 1))
    			DEVILBOX_DIR_PERM_WRONG=1
    		else
    			log_debug "Directory '${my_dir}' has correct permissions: ${PERM}"
    		fi
    	done < <(find "${search_dir}" -type d)
    done
    if [ "${DEVILBOX_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All devilbox directories have correct permissions"
    fi
    
    # Check allowed uid
    DEVILBOX_DIR_PERM_WRONG=0
    for search_dir in "${DEVILBOX_DIRS[@]}"; do
    	while read -r my_dir; do
    		PERM="$( file_get_uid "${my_dir}" )"
    		if [ "${PERM}" != "${MY_UID}" ]; then
    			log_err "Directory '${my_dir}' should have uid '${MY_UID}' Has: '${PERM}'"
    			RET_CODE=$(( RET_CODE + 1))
    			DEVILBOX_DIR_PERM_WRONG=1
    		else
    			log_debug "Directory '${my_dir}' has correct uid: ${PERM}"
    		fi
    	done < <(find "${search_dir}" -type d)
    done
    if [ "${DEVILBOX_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All devilbox directories have correct uid"
    fi
    
    # Check allowed gid
    DEVILBOX_DIR_PERM_WRONG=0
    for search_dir in "${DEVILBOX_DIRS[@]}"; do
    	while read -r my_dir; do
    		PERM="$( file_get_gid "${my_dir}" )"
    		if [ "${PERM}" != "${MY_GID}" ]; then
    			log_err "Directory '${my_dir}' should have gid '${MY_GID}' Has: '${PERM}'"
    			RET_CODE=$(( RET_CODE + 1))
    			DEVILBOX_DIR_PERM_WRONG=1
    		else
    			log_debug "Directory '${my_dir}' has correct gid: ${PERM}"
    		fi
    	done < <(find "${search_dir}" -type d)
    done
    if [ "${DEVILBOX_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All devilbox directories have correct gid"
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Devilbox File permissions
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking devilbox core file permissions"
    
    DEVILBOX_DIRS=(
    	"autostart"
    	"ca"
    	"cfg"
    	"compose"
    	"mod"
    	"supervisor"
    )
    
    # Check allowed directory permissions: 0644 0664 0666
    DEVILBOX_DIR_PERM_WRONG=0
    for search_file in "${DEVILBOX_DIRS[@]}"; do
    	while read -r my_file; do
    		PERM="$( file_get_perm "${my_file}" )"
    		# Private CA file
    		if [ "${my_file}" = "ca/devilbox-ca.key" ]; then
    			if [ "${PERM}" != "0600" ]; then
    				log_err "File '${my_file}' should have 0600 permissions. Has: ${PERM} permissions"
    				RET_CODE=$(( RET_CODE + 1))
    				DEVILBOX_DIR_PERM_WRONG=1
    			else
    				log_debug "File '${my_file}' has correct permissions: ${PERM}"
    			fi
    		# Executable files
    		elif echo "${my_file}" | grep -E '.+\.sh(-example)?$' >/dev/null; then
    			if [ "${PERM}" != "0755" ] && [ "${PERM}" != "0775" ] && [ "${PERM}" != "0777" ]; then
    				log_err "File '${my_file}' should have 0755, 0775 or 0777 permissions. Has: ${PERM} permissions"
    				RET_CODE=$(( RET_CODE + 1))
    				DEVILBOX_DIR_PERM_WRONG=1
    			else
    				log_debug "File '${my_file}' has correct permissions: ${PERM}"
    			fi
    		# All other files
    		else
    			if [ "${PERM}" != "0644" ] && [ "${PERM}" != "0664" ] && [ "${PERM}" != "0666" ]; then
    				log_err "File '${my_file}' should have 0644, 0664 or 0666 permissions. Has: ${PERM} permissions"
    				RET_CODE=$(( RET_CODE + 1))
    				DEVILBOX_DIR_PERM_WRONG=1
    			else
    				log_debug "File '${my_file}' has correct permissions: ${PERM}"
    			fi
    		fi
    	done < <(find "${search_file}" -type f)
    done
    if [ "${DEVILBOX_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All devilbox files have correct permissions"
    fi
    
    # Check allowed uid
    DEVILBOX_DIR_PERM_WRONG=0
    for search_file in "${DEVILBOX_DIRS[@]}"; do
    	while read -r my_file; do
    		PERM="$( file_get_uid "${my_file}" )"
    		if [ "${PERM}" != "${MY_UID}" ]; then
    			log_err "File '${my_file}' should have uid '${MY_UID}' Has: '${PERM}'"
    			RET_CODE=$(( RET_CODE + 1))
    			DEVILBOX_DIR_PERM_WRONG=1
    		else
    			log_debug "File '${my_file}' has correct uid: ${PERM}"
    		fi
    	done < <(find "${search_file}" -type f)
    done
    if [ "${DEVILBOX_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All devilbox files have correct uid"
    fi
    
    # Check allowed gid
    DEVILBOX_DIR_PERM_WRONG=0
    for search_file in "${DEVILBOX_DIRS[@]}"; do
    	while read -r my_file; do
    		PERM="$( file_get_gid "${my_file}" )"
    		if [ "${PERM}" != "${MY_GID}" ]; then
    			log_err "File '${my_file}' should have gid '${MY_GID}' Has: '${PERM}'"
    			RET_CODE=$(( RET_CODE + 1))
    			DEVILBOX_DIR_PERM_WRONG=1
    		else
    			log_debug "File '${my_file}' has correct gid: ${PERM}"
    		fi
    	done < <(find "${search_file}" -type f)
    done
    if [ "${DEVILBOX_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All devilbox files have correct gid"
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Check projects permissions
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking projects permissions"
    
    HOST_PATH_HTTPD_DATADIR="$( get_path "$( get_env_value "HOST_PATH_HTTPD_DATADIR" )" )"
    
    DATA_DIR_PERM_WRONG=0
    while read -r project; do
    	PERM="$( file_get_perm "${project}" )"
    	if [ "${PERM}" != "0755" ] && [ "${PERM}" != "0775" ] && [ "${PERM}" != "0777" ]; then
    		log_err "Directory '${project}' should have 0755, 0775 or 0777 permissions. Has: ${PERM} permissions"
    		RET_CODE=$(( RET_CODE + 1))
    		DATA_DIR_PERM_WRONG=1
    	else
    		log_debug "Directory '${project}' has correct permissions: ${PERM}"
    	fi
    done < <(get_sub_dirs_level_1 "${HOST_PATH_HTTPD_DATADIR}")
    if [ "${DATA_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All project dirs have correct permissions"
    fi
    
    DATA_DIR_PERM_WRONG=0
    while read -r project; do
    	PERM="$( file_get_uid "${project}" )"
    	if [ "${PERM}" != "${MY_UID}" ]; then
    		log_err "Directory '${project}' should have uid '${MY_UID}' Has: '${PERM}'"
    		RET_CODE=$(( RET_CODE + 1))
    		DATA_DIR_PERM_WRONG=1
    	else
    		log_debug "Directory '${project}' has correct uid: ${PERM}"
    	fi
    done < <(get_sub_dirs_level_1 "${HOST_PATH_HTTPD_DATADIR}")
    if [ "${DATA_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All project dirs have correct uid"
    fi
    
    DATA_DIR_PERM_WRONG=0
    while read -r project; do
    	PERM="$( file_get_gid "${project}" )"
    	if [ "${PERM}" != "${MY_GID}" ]; then
    		log_err "Directory '${project}' should have gid '${MY_GID}' Has: '${PERM}'"
    		RET_CODE=$(( RET_CODE + 1))
    		DATA_DIR_PERM_WRONG=1
    	else
    		log_debug "Directory '${project}' has correct gid: ${PERM}"
    	fi
    done < <(get_sub_dirs_level_1 "${HOST_PATH_HTTPD_DATADIR}")
    if [ "${DATA_DIR_PERM_WRONG}" = "0" ]; then
    	log_ok "All project dirs have correct gid"
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Check projects settings
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking projects settings"
    
    HOST_PATH_HTTPD_DATADIR="$( get_path "$( get_env_value "HOST_PATH_HTTPD_DATADIR" )" )"
    
    TLD_SUFFIX="$( get_env_value "TLD_SUFFIX" )"
    DNS_RECORD_WRONG=0
    while read -r project; do
    	VHOST="$( basename "${project}" ).${TLD_SUFFIX}"
    	if ! validate_dns "${VHOST}"; then
    		log_err "Project '${VHOST}' has no valid DNS record"
    		RET_CODE=$(( RET_CODE + 1))
    		DNS_RECORD_WRONG=1
    	else
    		log_debug "Project '${VHOST}' has valid DNS record"
    	fi
    done < <(get_sub_dirs_level_1 "${HOST_PATH_HTTPD_DATADIR}")
    if [ "${DNS_RECORD_WRONG}" = "0" ]; then
    	log_ok "All projects have valid DNS records"
    fi
    
    HTTPD_DOCROOT_DIR="$( get_env_value "HTTPD_DOCROOT_DIR" )"
    DOCROOT_WRONG=0
    while read -r project; do
    	if [ ! -d "${project}/${HTTPD_DOCROOT_DIR}" ]; then
    		log_err "Missing HTTPD_DOCROOT_DIR '${HTTPD_DOCROOT_DIR}' in: ${project}"
    		RET_CODE=$(( RET_CODE + 1))
    		DOCROOT_WRONG=1
    	else
    		log_debug "HTTPD_DOCROOT_DIR '${HTTPD_DOCROOT_DIR}' present in: ${project}"
    	fi
    done < <(get_sub_dirs_level_1 "${HOST_PATH_HTTPD_DATADIR}")
    if [ "${DOCROOT_WRONG}" = "0" ]; then
    	log_ok "All projects have valid HTTPD_DOCROOT_DIR"
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Check Customizations
    #--------------------------------------------------------------------------------------------------
    print_head_1 "Checking customizations"
    
    CUSTOMIZATIONS=0
    
    # vhost-gen
    HOST_PATH_HTTPD_DATADIR="$( get_path "$( get_env_value "HOST_PATH_HTTPD_DATADIR" )" )"
    HTTPD_TEMPLATE_DIR="$( get_env_value "HTTPD_TEMPLATE_DIR" )"
    while read -r project; do
    	if [ -f "${project}/${HTTPD_TEMPLATE_DIR}/apache22.yml" ]; then
    		log_note "[vhost-gen]  Custom Apache 2.2 vhost-gen config present in: ${project}/"
    		CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    	elif [ -f "${project}/${HTTPD_TEMPLATE_DIR}/apache24.yml" ]; then
    		log_note "[vhost-gen]  Custom Apache 2.4 vhost-gen config present in: ${project}/"
    		CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    	elif [ -f "${project}/${HTTPD_TEMPLATE_DIR}/nginx.yml" ]; then
    		log_note "[vhost-gen]  Custom Nginx vhost-gen config present in: ${project}/"
    		CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    	else
    		log_debug "[vhost-gen]  No custom configuration for: ${project}/"
    	fi
    done < <(get_sub_dirs_level_1 "${HOST_PATH_HTTPD_DATADIR}")
    
    # docker-compose.override.yml
    if [ -f "docker-compose.override.yml" ]; then
    	log_note "[docker]     Custom docker-compose.override.yml present"
    	CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    else
    	log_debug "[docker]     No custom docker-compose.override.yml present"
    fi
    
    # cfg/HTTPD/
    while read -r httpd; do
    	if find "cfg/${httpd}" | grep -E '\.conf$' >/dev/null; then
    		log_note "[httpd]      Custom config present in cfg/${httpd}/"
    		CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    	else
    		log_debug "[httpd]      No custom config present in cfg/${httpd}/"
    	fi
    done < <(grep -E '^#?HTTPD_SERVER=' env-example  | awk -F'=' '{print $2}')
    
    # cfg/php-ini-${version}/
    while read -r php_version; do
    	if find "cfg/php-ini-${php_version}" | grep -E '\.ini$' >/dev/null; then
    		log_note "[php.ini]    Custom config present in cfg/php-ini-${php_version}/"
    		CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    	else
    		log_debug "[php.ini]    No custom config present in cfg/php-ini-${php_version}/"
    	fi
    done < <(grep -E '^#?PHP_SERVER=' env-example  | awk -F'=' '{print $2}')
    
    # cfg/php-fpm-${version}/
    while read -r php_version; do
    	if find "cfg/php-fpm-${php_version}" | grep -E '\.conf$' >/dev/null; then
    		log_note "[php-fpm]    Custom config present in cfg/php-fpm-${php_version}/"
    		CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    	else
    		log_debug "[php-fpm]    No custom config present in cfg/php-fpm-${php_version}/"
    	fi
    done < <(grep -E '^#?PHP_SERVER=' env-example  | awk -F'=' '{print $2}')
    
    # cfg/MYSQL/
    while read -r mysql; do
    	if find "cfg/${mysql}" | grep -E '\.cnf$' >/dev/null; then
    		log_note "[mysql]      Custom config present in cfg/${mysql}/"
    		CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    	else
    		log_debug "[mysql]      No custom config present in cfg/${mysql}/"
    	fi
    done < <(grep -E '^#?MYSQL_SERVER=' env-example  | awk -F'=' '{print $2}')
    
    # cfg/php-startup-${version}/
    while read -r php_version; do
    	if find "cfg/php-startup-${php_version}" | grep -E '\.sh$' >/dev/null; then
    		log_note "[startup]    Custom script present in cfg/php-startup-${php_version}/"
    		CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    	else
    		log_debug "[startup]    No custom script present in cfg/php-startup-${php_version}/"
    	fi
    done < <(grep -E '^#?PHP_SERVER=' env-example  | awk -F'=' '{print $2}')
    
    # autostart/
    if find "autostart" | grep -E '\.sh$' >/dev/null; then
    	log_note "[startup]    Custom script present in autostart/"
    	CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    else
    	log_debug "[startup]    No custom script present in autostart/"
    fi
    
    # supervisor/
    if find "supervisor" | grep -E '\.conf$' >/dev/null; then
    	log_note "[supervisor] Custom config present in supervisor/"
    	CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    else
    	log_debug "[supervisor] No custom config present in supervisor/"
    fi
    
    # bash/
    if find "bash" | grep -E '\.sh$' >/dev/null; then
    	log_note "[bash]      Custom script present in bash/"
    	CUSTOMIZATIONS=$(( CUSTOMIZATIONS + 1 ))
    else
    	log_debug "[bash]      No custom script present in bash/"
    fi
    
    # Total?
    if [ "${CUSTOMIZATIONS}" = "0" ]; then
    	log_info "No custom configurations applied"
    fi
    
    
    #--------------------------------------------------------------------------------------------------
    # Summary
    #--------------------------------------------------------------------------------------------------
    print_head_1 "SUMMARY"
    
    if [ "${RET_CODE}" -gt "0" ]; then
    	log_err "Found ${RET_CODE} error(s)"
    	log_err "Devilbox might not work properly"
    	log_err "Fix the issues before submitting a bug report"
    	if [ "${CUSTOMIZATIONS}" -gt "0" ]; then
    		log_note "${CUSTOMIZATIONS} custom configurations applied. If you encounter issues, reset them first."
    	else
    		log_info "No custom configurations applied"
    	fi
    	log_info "Ensure to run 'docker-compose stop; docker-compose rm -f' on .env changes or custom configs"
    	exit 1
    else
    	log_ok "Found no errors"
    	if [ "${CUSTOMIZATIONS}" -gt "0" ]; then
    		log_note "${CUSTOMIZATIONS} custom configurations applied. If you encounter issues, reset them first."
    	else
    		log_info "No custom configurations applied"
    	fi
    	log_info "Ensure to run 'docker-compose stop; docker-compose rm -f' on .env changes or custom configs"
    	exit 0
    fi
    

    Log: docker-compose logs

    devilbox-httpd-1  | 2022/06/22 12:39:01 [notice] 1199#1199: signal process started
    devilbox-httpd-1  | watcherd: [2022-06-22 12:39:01] [OK]  TRIGGER succeeded: nginx -s stop
    devilbox-httpd-1  | watcherd: [2022-06-22 12:39:01] Using bash loop to watch for changes.
    devilbox-httpd-1  | 2022-06-22 12:39:01,335 INFO exited: httpd (exit status 0; expected)
    devilbox-httpd-1  | 2022-06-22 12:39:02,338 INFO spawned: 'httpd' with pid 1324
    devilbox-httpd-1  | 2022-06-22 12:39:03,340 INFO success: httpd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
    

    (Optional) Additional information

    Some of this settings I might use wrong. Not server expert. But I was adding them one by one a checking results and I ended up with all of those below.

    ; php.ini
    
    max_execution_time = 0
    upload_max_filesize = 16384M
    post_max_size = 16384M
    memory_limit = 16384M
    html_errors = 1
    error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
    ignore_repeated_errors = 1
    request_terminate_timeout = 3600
    
    ; xdebug.ini
    
    ; Defaults
    xdebug.mode=debug,develop,trace
    xdebug.start_with_request=trigger
    
    ; The WSL 2 way
    xdebug.discover_client_host=0
    xdebug.client_host=docker.for.wsl2.host.internal
    ; xdebug.client_host=localhost
    xdebug.client_port=9003
    
    ; idekey value is specific to Visual Studio Code
    xdebug.idekey=VSCODE
    
    xdebug.var_display_max_data=512
    xdebug.var_display_max_children=-1
    xdebug.var_display_max_depth=128
    
    ;mariadb.cnf
    
    [mysqld]
    ;key_buffer_size=16M
    
    [mariadb]
    connect_timeout=3600
    wait_timeout=3600
    net_read_timeout=3600
    net_write_timeout=3600
    interactive_timeout=3600
    thread_pool_idle_timeout=3600
    max_allowed_packet=4194304
    innodb_lock_wait_timeout=86400
    
    
    [mysqldump]
    ;quick
    
    #nginx.cnf
    charset utf-8;
    server_names_hash_bucket_size 128;
    fastcgi_keep_conn on;
    fastcgi_read_timeout 86400;
    keepalive_time 3600;
    keepalive_timeout  3600;
    client_body_timeout 3600;
    client_header_timeout 3600;
    send_timeout 3600;
    proxy_read_timeout 3600;
    proxy_connect_timeout 3600;
    proxy_send_timeout 3600;
    fastcgi_read_timeout 3600;
    lingering_time 3600;
    lingering_timeout 3600;
    
    Reviewed by bartech at 2022-06-22 19:26
  • 13. [Feature]: Add jasperreport addionnal container

    What is your idea or feature suggestion?

    Our need in one of our project is to use Jasperreport

    Benefits

    By default devilbox doesn't content any container of Jasperreport. I tried to use another docker image from bitnami: https://github.com/bitnami/bitnami-docker-jasperreports/blob/master/docker-compose.yml

    But I get an error of: port is already in use, I changed the port to 8080:8080, but there is another problem of connexion with database.

    I can't acces to jasperreport from localhost:8080

    How could we use this docker image as container of devilbox

    Where can we find information about this?

    https://github.com/TIBCOSoftware/JS-Docker

    Are you willing to provide a PR to address this?

    No response

    Reviewed by hielh at 2022-06-21 11:07
  • 14. Delayed message body loading

    Delayed message body loading

    Goal

    The Mail page was crashing for me because I had a lot of large emails that were more than the browser could load at once. This PR fixes that problem by delaying message body loading until each message is clicked to reveal the body (which is now loaded via AJAX). I'm happy to do this a different way if you'd prefer.

    DESCRIPTION

    Not much else to say...

    Reviewed by mmcev106 at 2022-06-20 20:19
  • 15. [Feature]: Add mercure.rocks addionnal container

    What is your idea or feature suggestion?

    Add support of mercure.rocks in devilbox to add more possibilities for developers with new features

    Benefits

    Allow user to make her application more live.

    Where can we find information about this?

    https://mercure.rocks/

    docker-compose.yml

    version: "3.7"
    
    services:
      caddy:
        image: dunglas/mercure
        restart: unless-stopped
        environment:
          # Uncomment the following line to disable HTTPS
          #SERVER_NAME: ':80'
          MERCURE_PUBLISHER_JWT_KEY: '!ChangeMe!'
          MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeMe!'
        # Uncomment the following line to enable the development mode
        #command: /usr/bin/caddy run -config /etc/caddy/Caddyfile.dev
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - caddy_data:/data
          - caddy_config:/config
    
    volumes:
      caddy_data:
      caddy_config:
    

    Are you willing to provide a PR to address this?

    No

    Reviewed by TheoD02 at 2022-06-17 14:24
  • 16. [Howto]:

    Have you already checked elsewhere?

    What are you struggling with?

    with version 1.11 mongodb starts, from version 2x and with mongodb 5.0 it does not start anymore. my environment is: linux mint 20.3 amd64 docker 20.10.16 docker-compose 1.29

    What have you tried already?

    as mentioned above, I have tried other versions

    What is your goal?

    run mongodb 5.0 with php 8.1

    Reviewed by zfranco55 at 2022-05-27 10:46
  • 17. [Feature]: OpenSearch

    What is your idea or feature suggestion?

    Possibility to use OpenSearch

    Benefits

    No response

    Where can we find information about this?

    https://opensearch.org/ https://github.com/opensearch-project/OpenSearch

    Are you willing to provide a PR to address this?

    No response

    Reviewed by jonatanaxe at 2022-05-25 18:58
DDEV-Local: a local PHP development environment system
DDEV-Local: a local PHP development environment system

ddev ddev is an open source tool that makes it simple to get local PHP development environments up and running in minutes. It's powerful and flexible

Jun 26, 2022
Demo of how you can run your Laravel app with Docker Compose. Look at docker-compose.yml and the docker folder. The rest is just a clean Laravel + Horizon install.

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Oct 22, 2021
Stacker - The environment for local web development, ready for use.
Stacker - The environment for local web development, ready for use.

Introduction English 简体中文 Why stacker? Stacker - This is a local environment for web development with everything you need. What is its benefit? You do

Apr 11, 2022
Quickly deploy a seedbox with self-hosted services and a web portal using Docker and docker-compose.
Quickly deploy a seedbox with self-hosted services and a web portal using Docker and docker-compose.

Seedbox Quickly deploy and configure a seedbox with self-hosted services and a web portal using Docker and a single docker-compose.yml file. Screensho

Jun 6, 2022
Docker Shortie, simplifying calls to CLI commands inside docker containers.

What is DockTie Is a simple wrapper script for commands inside docker container(s). So for instance, what you would normally run as: docker-compo

Mar 31, 2022
ServD - a Docker PHP development environment heavily inspired by Laravel Valet and Laradock

ServD ServD is a Docker PHP development environment heavily inspired by Laravel Valet and Laradock, it supports multiple projects within a working dir

May 13, 2022
Full PHP development environment for Docker.
Full PHP development environment for Docker.

Full PHP development environment based on Docker. Use Docker First - Learn About It Later! Join Us Awesome People Laradock is an MIT-licensed open sou

Jun 24, 2022
Docker Containers for simple Laravel development.
Docker Containers for simple Laravel development.

Docker containers of Laravel development. Docker Containers for simple Laravel development. Prerequisites This package only works for Linux users righ

May 19, 2022
🎲Neard is a portable WAMP software stack involving useful binaries, tools and applications for your web development.
🎲Neard is a portable WAMP software stack involving useful binaries, tools and applications for your web development.

About Neard is a portable WAMP software stack involving useful binaries, tools and applications for your web development. It also offers several versi

Jun 22, 2022
Up and running with small Docker environments
Up and running with small Docker environments

Vessel Up and running with small Docker dev environments. Documentation Full documentation can be found at https://vessel.shippingdocker.com. Install

Jun 29, 2022
Laravel 5 with Dockerized Gulp, PHP-FPM, MySQL and nginx using docker-compose

docker-laravel Laravel 5 with Dockerized PHP-FPM, MySQL and nginx using docker-compose Usage Get Composer docker-compose run --rm phpnginx curl -O htt

Feb 8, 2022
Docker with PHP 7.4 fpm, Nginx, Composer, PhpUnit and MaridaDB

Clean Docker with PHP Docker with PHP 7.4 fpm, Nginx, Composer, PhpUnit and MariaDB Starting app docker-compose up -d Main page

Apr 26, 2022
A package that allows you to generate simple and fast Docker configurations for your Laravel application!

A package that allows you to generate simple and fast Docker configurations for your Laravel application!

Dec 23, 2021
Symfony5 template w/ Docker config

Symfony5 w/ Docker config A project template in the following configuration: Symfony 5.2 PHP8 PostgreSQL 13.2 Separate Docker containers for Nginx, FP

May 14, 2022
Docker NAT容器自助部署php版本,实现从搭建到跑路的全生命周期功能。
Docker NAT容器自助部署php版本,实现从搭建到跑路的全生命周期功能。

DockerLabs-V1 游客可通过web页面直接创建出NAT容器,本项目从发布后将不再维护任何bug,以后有时间会出sdk重构版。 环境要求 使用了赛邮云发送短信号码,需要自己去申请appid和appkey填写到app_config.php文件中。需要修改所有html文件和api/kill.ph

Mar 4, 2022
The project provides a docker image for Files App(files.photo.gallery).
The project provides a docker image for Files App(files.photo.gallery).

For the purpose of learning,I replace the files.js with cracked version which just remove authorization code.

Apr 13, 2022
Multipurpose VIP Docker container images

VIP Container Images This repository is used to build Docker container images used, among others, by the VIP Local Development Environment. Images are

Mar 7, 2022
Shopware 6 app boilerplate + Symfony backend + Dockware docker dev environment 💙

Shopware 6 app boilerplate with Symfony backend This boilerplate template can be used to get up and running with a docker-based dev setup for Shopware

Nov 14, 2021
Ponto de partida para utilização do Docker Compose 💙✨
Ponto de partida para utilização do Docker Compose 💙✨

Docker-compose Docker | WSL2 | PHP | Nginx | MySQL Esse projeto fornece um ponto de partida para integrar diferentes serviços usando um arquivo Compos

Nov 9, 2021