How to Setup Docker Environment for Laravel Development
For web developer like us, we eventually has many projects sitting on our applications directory. Sometimes it turns out that different projects require different dependencies and even different versions of the same libraries. By changing the environment for one project globally, we change the configuration for all other projects, which later could introduce compatibility issues. This is extremely burdensome when we often switch between them and therefore difficult to maintain all running projects.
Another issue is in such configuration, we also don’t have the possibility to create a local environment for each application that would reflect its production environment. Thanks to Docker, our headache is gone. Using single configuration we are rest assured that we are using same libraries between our local machine and production environment.
Prerequisites
- Terminal and knowledge of some linux command(s).
- Docker installed. If you're running Linux Mint or Ubuntu derivatives, you can check my previous post about how to install Docker on Linux.
- Docker compose installed. Test by running this command on your terminal:
$ docker-compose
Download Laravel and Dependencies
We'll first download latest Laravel on our development machine. I'll use laravel-app for example. Shoot these command:
$ cd <your-project-directory>
$ git clone https://github.com/laravel/laravel.git laravel-app
Cloning into 'laravel-app'...
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 31135 (delta 1), reused 1 (delta 0), pack-reused 31127
Receiving objects: 100% (31135/31135), 9.69 MiB | 770.00 KiB/s, done.
Resolving deltas: 100% (18428/18428), done.
It will download and store it to laravel-app
directory. When it's done, we composer install as usual, but this time we run it using docker.
$ docker run --rm -v $(pwd):/app composer install
Unable to find image 'composer:latest' locally
latest: Pulling from library/composer
e6b0cf9c0882: Already exists
3c7a574e8632: Pull complete
2a6c65f587e9: Pull complete
ba33e4b639bb: Pull complete
a94182f10949: Pull complete
b06b2b4baeab: Pull complete
e6abb9ac3b49: Pull complete
6e8028c0b7a7: Pull complete
a1cc7bad024a: Pull complete
acc711a535ac: Pull complete
d5788687df72: Pull complete
c91a01e20dbd: Pull complete
b2c853bffcbc: Pull complete
3a0d79794dfc: Pull complete
0fac451fab2e: Pull complete
Digest: sha256:75a6a13680d0be7074f1c52f78f508751258d002c6e3934a7d5c332739f2b201
Status: Downloaded newer image for composer:latest
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 86 installs, 0 updates, 0 removals
- Installing symfony/polyfill-ctype (v1.13.1): Downloading (100%)
- Installing phpoption/phpoption (1.7.2): Downloading (100%)
- Installing vlucas/phpdotenv (v3.6.0): Downloading (100%)
- Installing symfony/css-selector (v5.0.2): Downloading (100%)
- Installing tijsverkoyen/css-to-inline-styles (2.2.2): Downloading (100%)
- Installing symfony/polyfill-php72 (v1.13.1): Downloading (100%)
- Installing symfony/polyfill-mbstring (v1.13.1): Downloading (100%)
- Installing symfony/var-dumper (v4.4.2): Downloading (100%)
- Installing symfony/routing (v4.4.2): Downloading (100%)
- Installing symfony/process (v4.4.2): Downloading (100%)
- Installing symfony/polyfill-php73 (v1.13.1): Downloading (100%)
- Installing symfony/polyfill-intl-idn (v1.13.1): Downloading (100%)
- Installing symfony/mime (v5.0.2): Downloading (100%)
- Installing symfony/http-foundation (v4.4.2): Downloading (100%)
- Installing symfony/event-dispatcher-contracts (v1.1.7): Downloading (100%)
- Installing psr/container (1.0.0): Downloading (100%)
- Installing symfony/event-dispatcher (v4.4.2): Downloading (100%)
- Installing psr/log (1.1.2): Downloading (100%)
- Installing symfony/debug (v4.4.2): Downloading (100%)
- Installing symfony/error-handler (v4.4.2): Downloading (100%)
- Installing symfony/http-kernel (v4.4.2): Downloading (100%)
- Installing symfony/finder (v4.4.2): Downloading (100%)
- Installing symfony/service-contracts (v2.0.1): Downloading (100%)
- Installing symfony/console (v4.4.2): Downloading (100%)
- Installing symfony/polyfill-iconv (v1.13.1): Downloading (100%)
- Installing doctrine/lexer (1.2.0): Downloading (100%)
- Installing egulias/email-validator (2.1.14): Downloading (100%)
- Installing swiftmailer/swiftmailer (v6.2.3): Downloading (100%)
- Installing paragonie/random_compat (v9.99.99): Downloading (100%)
- Installing ramsey/uuid (3.9.2): Downloading (100%)
- Installing psr/simple-cache (1.0.1): Downloading (100%)
- Installing opis/closure (3.5.1): Downloading (100%)
- Installing symfony/translation-contracts (v2.0.1): Downloading (100%)
- Installing symfony/translation (v4.4.2): Downloading (100%)
- Installing nesbot/carbon (2.28.0): Downloading (100%)
- Installing monolog/monolog (2.0.2): Downloading (100%)
- Installing league/flysystem (1.0.63): Downloading (100%)
- Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%)
- Installing doctrine/inflector (1.3.1): Downloading (100%)
- Installing league/commonmark (1.2.1): Downloading (100%)
- Installing league/commonmark-ext-table (v2.1.0): Downloading (100%)
- Installing laravel/framework (v6.11.0): Downloading (100%)
- Installing fideloper/proxy (4.2.2): Downloading (100%)
- Installing jakub-onderka/php-console-color (v0.2): Downloading (100%)
- Installing jakub-onderka/php-console-highlighter (v0.4): Downloading (100%)
- Installing nikic/php-parser (v4.3.0): Downloading (100%)
- Installing dnoegel/php-xdg-base-dir (v0.1.1): Downloading (100%)
- Installing psy/psysh (v0.9.12): Downloading (100%)
- Installing laravel/tinker (v2.1.0): Downloading (100%)
- Installing scrivo/highlight.php (v9.17.1.0): Downloading (100%)
- Installing filp/whoops (2.7.1): Downloading (100%)
- Installing facade/ignition-contracts (1.0.0): Downloading (100%)
- Installing facade/flare-client-php (1.3.1): Downloading (100%)
- Installing facade/ignition (1.14.0): Downloading (100%)
- Installing fzaninotto/faker (v1.9.1): Downloading (100%)
- Installing hamcrest/hamcrest-php (v2.0.0): Downloading (100%)
- Installing mockery/mockery (1.3.1): Downloading (100%)
- Installing nunomaduro/collision (v3.0.1): Downloading (100%)
- Installing sebastian/version (2.0.1): Downloading (100%)
- Installing sebastian/type (1.1.3): Downloading (100%)
- Installing sebastian/resource-operations (2.0.1): Downloading (100%)
- Installing sebastian/object-reflector (1.1.1): Downloading (100%)
- Installing sebastian/recursion-context (3.0.0): Downloading (100%)
- Installing sebastian/object-enumerator (3.0.3): Downloading (100%)
- Installing sebastian/global-state (3.0.0): Downloading (100%)
- Installing sebastian/exporter (3.1.2): Downloading (100%)
- Installing sebastian/environment (4.2.3): Downloading (100%)
- Installing sebastian/diff (3.0.2): Downloading (100%)
- Installing sebastian/comparator (3.0.2): Downloading (100%)
- Installing phpunit/php-timer (2.1.2): Downloading (100%)
- Installing phpunit/php-text-template (1.2.1): Downloading (100%)
- Installing phpunit/php-file-iterator (2.0.2): Downloading (100%)
- Installing phpunit/php-token-stream (3.1.1): Downloading (100%)
- Installing theseer/tokenizer (1.1.3): Downloading (100%)
- Installing sebastian/code-unit-reverse-lookup (1.0.1): Downloading (100%)
- Installing phpunit/php-code-coverage (7.0.10): Downloading (100%)
- Installing phpdocumentor/reflection-common (2.0.0): Downloading (100%)
- Installing phpdocumentor/type-resolver (1.0.1): Downloading (100%)
- Installing webmozart/assert (1.6.0): Downloading (100%)
- Installing phpdocumentor/reflection-docblock (4.3.4): Downloading (100%)
- Installing doctrine/instantiator (1.3.0): Downloading (100%)
- Installing phpspec/prophecy (1.10.1): Downloading (100%)
- Installing phar-io/version (2.0.1): Downloading (100%)
- Installing phar-io/manifest (1.0.3): Downloading (100%)
- Installing myclabs/deep-copy (1.9.4): Downloading (100%)
- Installing phpunit/phpunit (8.5.2): Downloading (100%)
symfony/var-dumper suggests installing ext-intl (To show region name in time zone dump)
symfony/routing suggests installing symfony/config (For using the all-in-one router or any loader)
symfony/routing suggests installing symfony/yaml (For using the YAML loader)
symfony/routing suggests installing symfony/expression-language (For using expression matching)
symfony/routing suggests installing doctrine/annotations (For using the annotation loader)
symfony/polyfill-intl-idn suggests installing ext-intl (For best performance)
symfony/event-dispatcher-contracts suggests installing psr/event-dispatcher
symfony/event-dispatcher suggests installing symfony/dependency-injection
symfony/http-kernel suggests installing symfony/browser-kit
symfony/http-kernel suggests installing symfony/config
symfony/http-kernel suggests installing symfony/dependency-injection
symfony/service-contracts suggests installing symfony/service-implementation
symfony/console suggests installing symfony/lock
egulias/email-validator suggests installing ext-intl (PHP Internationalization Libraries are required to use the SpoofChecking validation)
swiftmailer/swiftmailer suggests installing ext-intl (Needed to support internationalized email addresses)
swiftmailer/swiftmailer suggests installing true/punycode (Needed to support internationalized email addresses, if ext-intl is not installed)
paragonie/random_compat suggests installing ext-libsodium (Provides a modern crypto API that can be used to generate random bytes.)
ramsey/uuid suggests installing ext-libsodium (Provides the PECL libsodium extension for use with the SodiumRandomGenerator)
ramsey/uuid suggests installing ext-uuid (Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator)
ramsey/uuid suggests installing moontoast/math (Provides support for converting UUID to 128-bit integer (in string form).)
ramsey/uuid suggests installing ramsey/uuid-console (A console application for generating UUIDs with ramsey/uuid)
ramsey/uuid suggests installing ramsey/uuid-doctrine (Allows the use of Ramsey\Uuid\Uuid as Doctrine field type.)
ramsey/uuid suggests installing paragonie/random-lib (Provides RandomLib for use with the RandomLibAdapter)
symfony/translation suggests installing symfony/config
symfony/translation suggests installing symfony/yaml
monolog/monolog suggests installing graylog2/gelf-php (Allow sending log messages to a GrayLog2 server)
monolog/monolog suggests installing doctrine/couchdb (Allow sending log messages to a CouchDB server)
monolog/monolog suggests installing ruflin/elastica (Allow sending log messages to an Elastic Search server)
monolog/monolog suggests installing elasticsearch/elasticsearch (Allow sending log messages to an Elasticsearch server via official client)
monolog/monolog suggests installing php-amqplib/php-amqplib (Allow sending log messages to an AMQP server using php-amqplib)
monolog/monolog suggests installing ext-amqp (Allow sending log messages to an AMQP server (1.0+ required))
monolog/monolog suggests installing ext-mongodb (Allow sending log messages to a MongoDB server (via driver))
monolog/monolog suggests installing mongodb/mongodb (Allow sending log messages to a MongoDB server (via library))
monolog/monolog suggests installing aws/aws-sdk-php (Allow sending log messages to AWS services like DynamoDB)
monolog/monolog suggests installing rollbar/rollbar (Allow sending log messages to Rollbar)
monolog/monolog suggests installing php-console/php-console (Allow sending log messages to Google Chrome)
league/flysystem suggests installing league/flysystem-eventable-filesystem (Allows you to use EventableFilesystem)
league/flysystem suggests installing league/flysystem-rackspace (Allows you to use Rackspace Cloud Files)
league/flysystem suggests installing league/flysystem-azure (Allows you to use Windows Azure Blob storage)
league/flysystem suggests installing league/flysystem-webdav (Allows you to use WebDAV storage)
league/flysystem suggests installing league/flysystem-aws-s3-v2 (Allows you to use S3 storage with AWS SDK v2)
league/flysystem suggests installing league/flysystem-aws-s3-v3 (Allows you to use S3 storage with AWS SDK v3)
league/flysystem suggests installing spatie/flysystem-dropbox (Allows you to use Dropbox storage)
league/flysystem suggests installing srmklive/flysystem-dropbox-v2 (Allows you to use Dropbox storage for PHP 5 applications)
league/flysystem suggests installing league/flysystem-cached-adapter (Flysystem adapter decorator for metadata caching)
league/flysystem suggests installing league/flysystem-sftp (Allows you to use SFTP server storage via phpseclib)
league/flysystem suggests installing league/flysystem-ziparchive (Allows you to use ZipArchive adapter)
league/commonmark suggests installing league/commonmark-extras (Library of useful extensions including smart punctuation)
laravel/framework suggests installing ext-gd (Required to use Illuminate\Http\Testing\FileFactory::image().)
laravel/framework suggests installing ext-memcached (Required to use the memcache cache driver.)
laravel/framework suggests installing ext-pcntl (Required to use all features of the queue worker.)
laravel/framework suggests installing ext-redis (Required to use the Redis cache and queue drivers.)
laravel/framework suggests installing aws/aws-sdk-php (Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.0).)
laravel/framework suggests installing doctrine/dbal (Required to rename columns and drop SQLite columns (^2.6).)
laravel/framework suggests installing guzzlehttp/guzzle (Required to use the Mailgun mail driver and the ping methods on schedules (^6.0).)
laravel/framework suggests installing league/flysystem-aws-s3-v3 (Required to use the Flysystem S3 driver (^1.0).)
laravel/framework suggests installing league/flysystem-cached-adapter (Required to use the Flysystem cache (^1.0).)
laravel/framework suggests installing league/flysystem-sftp (Required to use the Flysystem SFTP driver (^1.0).)
laravel/framework suggests installing moontoast/math (Required to use ordered UUIDs (^1.1).)
laravel/framework suggests installing nyholm/psr7 (Required to use PSR-7 bridging features (^1.2).)
laravel/framework suggests installing pda/pheanstalk (Required to use the beanstalk queue driver (^4.0).)
laravel/framework suggests installing psr/http-message (Required to allow Storage::put to accept a StreamInterface (^1.0).)
laravel/framework suggests installing pusher/pusher-php-server (Required to use the Pusher broadcast driver (^4.0).)
laravel/framework suggests installing symfony/cache (Required to PSR-6 cache bridge (^4.3.4).)
laravel/framework suggests installing symfony/psr-http-message-bridge (Required to use PSR-7 bridging features (^1.2).)
laravel/framework suggests installing wildbit/swiftmailer-postmark (Required to use Postmark mail driver (^3.0).)
psy/psysh suggests installing ext-pcntl (Enabling the PCNTL extension makes PsySH a lot happier :))
psy/psysh suggests installing ext-pdo-sqlite (The doc command requires SQLite to work.)
psy/psysh suggests installing hoa/console (A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit.)
filp/whoops suggests installing whoops/soap (Formats errors as SOAP responses)
facade/ignition suggests installing laravel/telescope (^2.0)
sebastian/global-state suggests installing ext-uopz (*)
phpunit/php-code-coverage suggests installing ext-xdebug (^2.7.2)
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0.0)
phpunit/phpunit suggests installing ext-soap (*)
phpunit/phpunit suggests installing ext-xdebug (*)
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
The above command "docker run --rm -v $(pwd):/app composer install
" means:
docker run
: Run a command in a new container.--rm
: ensure this container does not linger around following the install.-v $(pwd):/app
is used to mount the current directory on the host (your machine) to/app
in the container — this is where composer running inside the container expects to find a composer.json-v $(pwd):/app
will also ensure that the vendor folder created by composer inside the container is also visible on our machine.composer install
: runs the composer command on the container.
Configure Laravel Environment
After we've successfully installed Laravel, now it's time to configure our environment. Building your applications with Docker Compose simplifies the process of setting up and versioning your infrastructure. To set up our Laravel application, we will write a docker-compose file that defines our web server, database, and application services.
Create file called docker-compose.yml
in our Laravel directory:
$ vi ~/laravel-app/docker-compose.yml
Make sure to replace the root password for
MYSQL_ROOT_PASSWORD
, defined as an environment variable under the database service, with a strong password of your choice.
Let's fill it line by line.
version: '3'
services:
# Our services definition below:
Web server
First, we'll define our first service. It's our web server powered by Nginx.
Enter these into our docker-compose.yml
file:
#Nginx Service
web:
image: nginx
container_name: web
restart: unless-stopped
tty: true
ports:
- "8080:80"
networks:
- app-network
volumes:
- ./:/var/www
- ./nginx/conf.d/:/etc/nginx/conf.d/
We map port 8080
on the host to 80
in the container. This is so that we can access 0.0.0.0:8080
whilst in development and won’t need to mess around with host names.
We use a single volume definition ./:/var/www
to mount the everything in the current directory on the host into /var/www
in the container. This will allow us to make changes to our source code and have them reflected in the running application immediately.
Note that we also bind /nginx/conf.d
to /etc/nginx/conf.d
. The purpose is to set our Laravel's Nginx virtual host definition. We'll create the file later.
Database
Next step is defining our MariaDB database. Let's add to our docker-compose.yml
file:
#MariaDB Service
database:
image: mariadb
container_name: database
restart: unless-stopped
tty: true
ports:
- "33060:3306"
environment:
MYSQL_DATABASE: homestead
MYSQL_USER: homestead
MYSQL_PASSWORD: your_password
MYSQL_ROOT_PASSWORD: your_mysql_root_password
networks:
- app-network
volumes:
- dbdata:/var/lib/mysql
We reference that volume by using the format <name>:<dir>
So this is saying "mount the directory /var/lib/mysql
from the volume named dbdata
"
We set the required environment variables: MYSQL_DATABASE
, MYSQL_USER
, MYSQL_PASSWORD
, and MYSQL_ROOT_PASSWORD
.
We used homestead
as the database and user name as these values match what can be found in the default .env
that ships with Laravel, meaning we won’t have to change it there. We only need to set the password and make sure they're same between this file and your Laravel .env
file.
Finally we create an addition port mapping of 33060
on the host to the regular 3306
inside the container. This is done solely to allow external tools easier access to the database whilst in development — it will not be needed in the production setup.
Application
Now it's time to add PHP service definition. Again, let's add to our docker-compose.yml
file:
#PHP Service
app:
build:
context: .
dockerfile: Dockerfile
#image: digitalocean.com/php
container_name: app
restart: unless-stopped
tty: true
environment:
SERVICE_NAME: app
SERVICE_TAGS: dev
working_dir: /var/www
networks:
- app-network
volumes:
- ./:/var/www
Extra Configuration
Add these lines on the bottom of our docker-compose.yml
file:
#Docker Networks
networks:
app-network:
driver: bridge
volumes:
dbdata:
Create new file called Dockerfile
on your laravel-app
directory. This file will define all dependencies and extra setup.
$ vi Dockerfile
The Dockerfile
file content is below:
FROM php:7.4-fpm
# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/
# Set working directory
WORKDIR /var/www
RUN apt update && apt install -y \
build-essential \
libpng-dev \
libjpeg62-turbo-dev \
libfreetype6-dev \
locales \
zip \
jpegoptim optipng pngquant gifsicle \
vim \
unzip \
git \
curl \
libzip-dev \
libmcrypt-dev \
libxml2-dev \
libonig-dev
# Clear cache
#RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-freetype --with-jpeg
RUN docker-php-ext-install -j$(nproc) gd
# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www
# Copy existing application directory contents
COPY . /var/www
# Copy existing application directory permissions
COPY --chown=www:www . /var/www
# Change current user to www
USER www
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
Next step we'll create Nginx configuration.
$ mkdir -p nginx/conf.d
$ vi nginx/conf.d/vhost.conf
The configuration itself is just like standard Laravel configuration on Nginx:
server {
listen 80;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}
Finally, our whole docker-compose.yml
should be like this:
version: '3'
services:
# Our services definition below:
#Nginx Service
web:
image: nginx
container_name: web
restart: unless-stopped
tty: true
ports:
- "8080:80"
networks:
- app-network
volumes:
- ./:/var/www
- ./nginx/conf.d/:/etc/nginx/conf.d/
#MariaDB Service
database:
image: mariadb
container_name: database
restart: unless-stopped
tty: true
ports:
- "33060:3306"
environment:
MYSQL_DATABASE: homestead
MYSQL_USER: homestead
MYSQL_PASSWORD: your_password
MYSQL_ROOT_PASSWORD: your_mysql_root_password
networks:
- app-network
volumes:
- dbdata:/var/lib/mysql
#PHP Service
app:
build:
context: .
dockerfile: Dockerfile
#image: digitalocean.com/php
container_name: app
restart: unless-stopped
tty: true
environment:
SERVICE_NAME: app
SERVICE_TAGS: dev
working_dir: /var/www
networks:
- app-network
volumes:
- ./:/var/www
#Docker Networks
networks:
app-network:
driver: bridge
volumes:
dbdata:
Starting Services
Now is the time for test our docker-compose file. The command docker-compose up
will download necessary images and start all services.
To run the process in daemon mode use extra parameter
-d
.
$ docker-compose up
When running this command for the first time, it should take a while depends on your internet connection. When it's completed successfully, we can issue this command:
$ docker ps
You should see something similar below:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ef8667f2b421 nginx "nginx -g 'daemon of…" 18 minutes ago Up 18 minutes 0.0.0.0:8080->80/tcp web
fba96af44248 laravelapp_app "docker-php-entrypoi…" 18 minutes ago Up 18 minutes 9000/tcp app
35d7c5997bbc mariadb "docker-entrypoint.s…" 18 minutes ago Up 18 minutes 0.0.0.0:33060->3306/tcp database
Laravel Initialization
Just like usual Laravel installation, we must copy .env-example
file to .env
and set encryption key. Enter this command:
$ cp .env.example .env
$ docker-compose exec app php artisan key:generate
Application key set successfully.
The 'docker-compose
' command above means: Execute the command 'php artisan key:generate
' inside the container used by the service 'app
'. Another example, if we want to run migration and then seed the database, we uses artisan db:migrate --seed
.
$ docker-compose exec app php artisan db:migrate --seed
Stopping Services
If you're already familiar with system administration, we usually use the keyword up
and down
as parameter to change service running condition. We've learnt above that we're using command docker-compose up
to bring all services up. Now, to stop the services, we use docker-compose down
.
$ docker-compose down
Stopping database ... done
Stopping web ... done
Stopping app ... done
Removing database ... done
Removing web ... done
Removing app ... done
Removing network laravelapp_app-network
Final Words
I hope that you now know how to install Setup Docker Environment for Laravel Development on Linux Mint 19. I'm a mere human afterall, I may made typo or mistakes. If you run into any issues or have any feedback feel free to drop a comment below.