This notes is simplify version of long series of Docker Setup for local web development project write by tech.osteel.me. Adjustments were made based on my habit and repetitive step when starting new laravel new project.
- Ensure Docker Desktop with Docker Compose has been installed.
- Create project folder (for example: /Users/macto/Development/laravel-project).
- Change project name inside this notes with yours.
- For folder:
laravel-project
. - For inside config files:
laravelproject
.
- For folder:
- In this notes I use only below services:
- laravel (as backend)
- mysql (as database)
- phpmyadmin (as database management ui)
final folder structure for this setup as per below:
laravel-project/
├── .docker/
│ ├── mysql/
│ │ └── my.cnf
│ └── nginx/
│ └── conf.d/
│ └── backend.conf
│ └── phpmyadmin.conf
├── src/
│ └── backend/
│ └── Dockerfile
├── .env
├── .env.example
├── .gitignore
└── docker-compose.yml
- Copy, paste and save as docker-compose.yml for below minimal configuration:
version: '3.8'
# Services
services:
# Nginx Service
nginx:
build: ./.docker/nginx
ports:
- 80:80
- 443:443
volumes:
- ./src/backend:/var/www/backend
- ./.docker/nginx/conf.d:/etc/nginx/conf.d
- phpmyadmindata:/var/www/phpmyadmin
- ./.docker/nginx/certs:/etc/nginx/certs
depends_on:
- backend
- phpmyadmin
# Backend Service
backend:
build:
context: ./src/backend
target: backend
working_dir: /var/www/backend
volumes:
- ./src/bend:/var/www/backend
- ./.docker/backend/init:/opt/files/init
- ./.docker/nginx/certs:/usr/local/share/ca-certificates
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
# MySQL Service
mysql:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: laravelproject
volumes:
- ./.docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
- mysqldata:/var/lib/mysql
healthcheck:
test: mysqladmin ping -h 127.0.0.1 -u root --password=$$MYSQL_ROOT_PASSWORD
interval: 5s
retries: 10
# PhpMyAdmin Service
phpmyadmin:
image: phpmyadmin/phpmyadmin:5-fpm-alpine
environment:
PMA_HOST: mysql
volumes:
- phpmyadmindata:/var/www/html
depends_on:
mysql:
condition: service_healthy
# Volumes
volumes:
mysqldata:
phpmyadmindata:
- create
Dockerfile
file in.docker/nginx/
- copy below code to new created
Dockerfile
FROM nginx:1.19-alpine
# Install packages
RUN apk --update --no-cache add openssl
- create
backend
folder inlaravel-project/src/
- create
Dockerfile
file inlaravel-project/src/backend/
- copy below code:
FROM php:8.0-fpm-alpine as backend
# Import extension installer
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/bin/
# Install extensions
RUN install-php-extensions pdo_mysql bcmath opcache redis
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
# Configure PHP
COPY .docker/php.ini $PHP_INI_DIR/conf.d/opcache.ini
# Use the default development configuration
RUN mv $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
# Install extra packages
RUN apk --no-cache add bash mysql-client mariadb-connector-c-dev
FROM backend as worker
# Start worker
CMD ["php", "/var/www/bend/artisan", "queue:work"]
- create
.docker
folder inlaravel-project/src/backend/
- create
php.ini
file inside newly created.docker
folder - copy below code to the
php.ini
:
[opcache]
opcache.enable=1
opcache.revalidate_freq=0
opcache.validate_timestamps=1
opcache.max_accelerated_files=10000
opcache.memory_consumption=192
opcache.max_wasted_percentage=10
opcache.interned_strings_buffer=16
opcache.fast_shutdown=1
- create
backend.conf
file in.docker/nginx/conf.d
- copy below code:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name backend.laravelproject.test *.ngrok.io;
root /var/www/backend/public;
ssl_certificate /etc/nginx/certs/laravelproject.test.crt;
ssl_certificate_key /etc/nginx/certs/laravelproject.test.key;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_pass bend:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
server {
listen 80;
listen [::]:80;
server_name backend.laravelproject.test;
return 301 https://$server_name$request_uri;
}
- create
phpmyadmin.conf
file in.docker/nginx/conf.d
- copy below code:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name phpmyadmin.laravelproject.test;
root /var/www/phpmyadmin;
index index.php;
ssl_certificate /etc/nginx/certs/laravelproject.test.crt;
ssl_certificate_key /etc/nginx/certs/laravelproject.test.key;
location ~* \.php$ {
fastcgi_pass phpmyadmin:9000;
root /var/www/html;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
}
server {
listen 80;
listen [::]:80;
server_name phpmyadmin.laravelproject.test;
return 301 https://$server_name$request_uri;
}
- create
mysql
folder inlaravel-project/.docker
- create
my.cnf
file in newly created mysql folder - copy below code to
my.cnf
file
[mysqld]
collation-server = utf8mb4_unicode_ci
character-set-server = utf8mb4
default-authentication-plugin = mysql_native_password
- do this in root folder
- do the same in
src/backend
- create
init
file inlaravel-project/.docker/backend
- copy below code:
#!/bin/bash
# Install Composer dependencies
composer install -d "/var/www/backend"
# Deal with the .env file if necessary
if [ ! -f "/var/www/backend/.env" ]; then
# Create .env file
cat > "/var/www/backend/.env" << EOF
APP_NAME=laravelproject
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://backend.laravelproject.test
LOG_CHANNEL=single
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravelproject
DB_USERNAME=root
DB_PASSWORD=root
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=redis
REDIS_HOST=redis
SESSION_DRIVER=file
EOF
# Generate application key
php "/var/www/backend/artisan" key:generate --ansi
fi
# Database
php "/var/www/backend/artisan" migrate
- update
init
permission
$ chmod +x .docker/backend/init
- create
laravelproject.sh
inlaravel-project
root folder - change permission
$ chmod +x laravelproject.sh
- copy below code (to check and edit any github account related setup):
#!/bin/bash
#######################################
# FUNCTIONS
#######################################
# Run an Artisan command
artisan () {
docker-compose run --rm bend php artisan "${@:1}"
}
# Build all of the images or the specified one
build () {
docker-compose build "${@:1}"
}
# Run a Composer command
composer () {
docker-compose run --rm bend composer "${@:1}"
}
# Remove the entire Docker environment
destroy () {
read -p "This will delete containers, volumes and images. Are you sure? [y/N]: " -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit; fi
docker-compose down -v --rmi all --remove-orphans
}
# Stop and destroy all containers
down () {
docker-compose down "${@:1}"
}
# Create and start the containers and volumes
start(){
docker-compose up -d
}
# Stop the containers
stop () {
docker-compose stop
}
# Display and tail the logs
logs () {
docker-compose logs -f "${@:1}"
}
# Restart the containers
restart () {
stop && start
}
# Run a Yarn command
yarn () {
docker-compose run --rm frontend yarn "${@:1}"
}
# Create .env from .env.example
env () {
if [ ! -f .env ]; then
cp .env.example .env
fi
}
# Initialise the Docker environment and the application
init () {
env \
&& down -v \
&& build \
&& docker-compose run --rm --entrypoint="//opt/files/init" backend \
&& yarn install
if [ ! -f .docker/nginx/certs/laravelproject.test.crt ]; then
cert_generate
fi
start && cert_install
}
# Update the Docker environment
update () {
git pull \
&& build \
&& composer install \
&& artisan migrate \
&& yarn install \
&& start
}
# Clone or update the repositories
repositories () {
repos=(backend)
cd src
for repo in "${repos[@]}";
do
git clone "[email protected]:username/${repo}.git" "$repo" || (cd "$repo" ; git pull ; cd ..) || true
done
cd ..
}
# Generate a wildcard certificate
cert_generate () {
rm -Rf .docker/nginx/certs/laravelproject.test.*
docker-compose run --rm nginx sh -c "cd /etc/nginx/certs && touch openssl.cnf && cat /etc/ssl/openssl.cnf > openssl.cnf && echo \"\" >> openssl.cnf && echo \"[ SAN ]\" >> openssl.cnf && echo \"subjectAltName=DNS.1:laravelproject.test,DNS.2:*.laravelproject.test\" >> openssl.cnf && openssl req -x509 -sha256 -nodes -newkey rsa:4096 -keyout laravelproject.test.key -out heartweb.test.crt -days 3650 -subj \"/CN=*.laravelproject.test\" -config openssl.cnf -extensions SAN && rm openssl.cnf"
}
cert_install () {
if [[ "$OSTYPE" == "darwin"* ]]; then
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain .docker/nginx/certs/laravelproject.test.crt
elif [[ "$OSTYPE" == "linux-gnu" ]]; then
sudo ln -s "$(pwd)/.docker/nginx/certs/laravelproject.test.crt" /usr/local/share/ca-certificates/laravelproject.test.crt
sudo update-ca-certificates
else
echo "Could not install the certificate on the host machine, please do it manually"
fi
docker-compose exec bend update-ca-certificates
}
#######################################
# MENU
#######################################
case "$1" in
artisan)
artisan "${@:2}"
;;
build)
build "${@:2}"
;;
composer)
composer "${@:2}"
;;
destroy)
destroy
;;
down)
down "${@:2}"
;;
logs)
logs "${@:2}"
;;
restart)
restart
;;
start)
start
;;
stop)
stop
;;
yarn)
yarn "${@:2}"
;;
init)
init
;;
update)
update
;;
repositories)
repositories
;;
cert)
case "$2" in
generate)
cert_generate
;;
install)
cert_install
;;
*)
cat << EOF
Certificate management commands.
Usage:
demo cert <command>
Available commands:
generate .................................. Generate a new certificate
install ................................... Install the certificate
EOF
;;
esac
;;
*)
cat << EOF
Command line interface for the Docker-based web development environment demo.
Usage:
demo <command> [options] [arguments]
Available commands:
artisan ................................... Run an Artisan command
build [image] ............................. Build all of the images or the specified one
composer .................................. Run a Composer command
cert ...................................... Certificate management commands
generate .............................. Generate a new certificate
install ............................... Install the certificate
destroy ................................... Remove the entire Docker environment
down [-v] ................................. Stop and destroy all containers
Options:
-v .................... Destroy the volumes as well
init ...................................... Initialise the Docker environment and the application
logs [container] .......................... Display and tail the logs of all containers or the specified one's
restart ................................... Restart the containers
start ..................................... Start the containers
stop ...................................... Stop the containers
update .................................... Update the Docker environment
yarn ...................................... Run a Yarn command
EOF
exit 1
;;
esac
- edit
~/.bashrc
- copy below code to last line of
.bashrc
function laravelproject {
cd /PATH/TO/YOUR/PROJECT && bash demo $*
cd -
}
- save and run command
$ source ~/.bashrc
to re-load.bashrc
run below command:
$ docker compose up -d
edit /etc/hosts
file with below:
127.0.0.1 backend.laravelproject.test phpmyadmin.laravelproject.test
run below command:
$ docker compose images
run below command:
$ docker compose ps
run below command:
$ docker compose stop