Hey there DEV.to community!
In the last part, we've covered how to dockerize a Laravel app. That was a great way to know how stuff goes around in a docker container and get you started before moving to the next level!
Although it is possible to run all your requirements inside a single container it is not a great practice. (Thanks to .
Some Laravel apps need Node to run if you are using Laravel as a full-stack framework. So installing Node.js is a must:
RUN apk add --update nodejs npm
Then simply copy the current directory inside /var/www/html and change the working directory as well:
COPY . /var/www/html
WORKDIR /var/www/html
Well, this part gets a little tricky but it is pretty simple. Since we are going to mount /var/www/html as a volume to be shared between other containers, the data inside this directory cannot be changed while building the image and needs to be changed after the container has run. Thus, we need to create a .env file and copy it into the Laravel directory later on:
RUN printf "\
APP_NAME=$APP_NAME\n\
APP_ENV=$APP_ENV\n\
APP_KEY=$APP_KEY\n\
APP_DEBUG=$APP_DEBUG\n\
APP_URL=$APP_URL\n\
LOG_CHANNEL=$LOG_CHANNEL\n\
LOG_DEPRECATIONS_CHANNEL=$LOG_DEPRECATIONS_CHANNEL\n\
LOG_LEVEL=$LOG_LEVEL\n\
DB_CONNECTION=$DB_CONNECTION\n\
DB_HOST=$DB_HOST\n\
DB_PORT=$DB_PORT\n\
DB_DATABASE=$DB_DATABASE\n\
DB_USERNAME=$DB_USERNAME\n\
DB_PASSWORD=$DB_PASSWORD\n\
BROADCAST_DRIVER=$BROADCAST_DRIVER\n\
CACHE_DRIVER=$CACHE_DRIVER\n\
FILESYSTEM_DISK=$FILESYSTEM_DISK\n\
QUEUE_CONNECTION=$QUEUE_CONNECTION\n\
SESSION_DRIVER=$SESSION_DRIVER\n\
SESSION_LIFETIME=$SESSION_LIFETIME\n\
MEMCACHED_HOST=$MEMCACHED_HOST\n\
REDIS_HOST=$REDIS_HOST\n\
REDIS_PASSWORD=$REDIS_PASSWORD\n\
REDIS_PORT=$REDIS_PORT\n\
MAIL_MAILER=$MAIL_MAILER\n\
MAIL_HOST=$MAIL_HOST\n\
MAIL_PORT=$MAIL_PORT\n\
MAIL_USERNAME=$MAIL_USERNAME\n\
MAIL_PASSWORD=$MAIL_PASSWORD\n\
MAIL_ENCRYPTION=$MAIL_ENCRYPTION\n\
MAIL_FROM_ADDRESS=$MAIL_FROM_ADDRESS\n\
MAIL_FROM_NAME=$MAIL_FROM_NAME\n\
AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID\n\
AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY\n\
AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION\n\
AWS_BUCKET=$AWS_BUCKET\n\
AWS_USE_PATH_STYLE_ENDPOINT=$AWS_USE_PATH_STYLE_ENDPOINT\n\
PUSHER_APP_ID=$PUSHER_APP_ID\n\
PUSHER_APP_KEY=$PUSHER_APP_KEY\n\
PUSHER_APP_SECRET=$PUSHER_APP_SECRET\n\
PUSHER_HOST=$PUSHER_HOST\n\
PUSHER_PORT=$PUSHER_PORT\n\
PUSHER_SCHEME=$PUSHER_SCHEME\n\
PUSHER_APP_CLUSTER=$PUSHER_APP_CLUSTER\n\
VITE_APP_NAME=$VITE_APP_NAME\n\
VITE_PUSHER_APP_KEY=$VITE_PUSHER_APP_KEY\n\
VITE_PUSHER_HOST=$VITE_PUSHER_HOST\n\
VITE_PUSHER_PORT=$VITE_PUSHER_PORT\n\
VITE_PUSHER_SCHEME=$VITE_PUSHER_SCHEME\n\
VITE_PUSHER_APP_CLUSTER=$VITE_PUSHER_APP_CLUSTER\n\
BUCKET_ENDPOINT_URL=$BUCKET_ENDPOINT_URL\n\
BUCKET_ACCESS_KEY=$BUCKET_ACCESS_KEY\n\
BUCKET_SECRET_KEY=$BUCKET_SECRET_KEY\n\
BUCKET_DEFAULT_REGION=$BUCKET_DEFAULT_REGION\n\
BUCKET_NAME=$BUCKET_NAME" > /usr/local/laravel.env
I've saved this file /usr/local/laravel.env which will be used in our custom start-up script.
Now it's time to install PHP and Node.js dependencies:
RUN composer install
RUN npm install
And expose port 9000. This port is used by PHP-FPM:
EXPOSE 9000
In the next step we need to create a custom start-up script as bellow:
RUN printf "\
chmod -R o+w /var/www/html/storage\n\
chown -R root:root /var/www/html/storage\n\
cp /usr/local/laravel.env /var/www/html/.env\n\
php-fpm\n\
" > /start.sh
This is done since only one command can be run inside a container and a container will stop when the command has been completed.
Give the script permission to be executed:
RUN chmod +x "/start.sh"
And finally, set it as our entrypoint:
ENTRYPOINT "/start.sh"
NGINX Dockerfile
We need some customization to run NGINX the way we need it.
Create a file called Dockerfile.nginx and put the code below in it:
FROM nginx:stable-alpine AS base
RUN printf "\
server {\n\
listen 80;\n\
index index.php index.html;\n\
error_log /var/log/nginx/error.log;\n\
access_log /var/log/nginx/access.log;\n\
root /var/www/html/public;\n\
location ~ \.php$ {\n\
try_files \$uri =404;\n\
fastcgi_split_path_info ^(.+\.php)(/.+)$;\n\
fastcgi_pass laravel:9000;\n\
fastcgi_index index.php;\n\
include fastcgi_params;\n\
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;\n\
fastcgi_param PATH_INFO \$fastcgi_path_info;\n\
}\n\
location / {\n\
try_files \$uri \$uri/ /index.php?\$query_string;\n\
gzip_static on;\n\
}\n\
}\n" > /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
This Dockerfile uses FROM nginx:stable-alpine as its base image.
We need to customize the way NGINX behaves to meet Laravel's requirements. The configuration that is saved inside /etc/nginx/conf.d/default.conf is the configuration recommended by Laravel's official documentation with a few minor tweaks:
- Changed the fast_cgi address to
laravel:9000which will be available inside a private network we will define late inside adocker-compose.ymlfile. - Changed the root of our website to
/var/www/html/public
Docker compose
Now that we have our customized Laravel and NGINX images, it is time to define the relation of these images and a few more images.
Create a file called docker-compose.yml and put the code below in it:
name: my-laravel
networks:
laravel-network:
driver: bridge
volumes:
laravel-db:
driver: local
laravel-app:
driver: local
services:
laravel:
build:
context: .
dockerfile: Dockerfile.laravel
args:
- APP_NAME=Laravel
- APP_ENV=local
- APP_KEY=
- APP_DEBUG=true
- APP_URL=YOUR_APP_URL
- LOG_CHANNEL=stack
- LOG_DEPRECATIONS_CHANNEL=null
- LOG_LEVEL=debug
- DB_CONNECTION=mysql
- DB_HOST=db
- DB_PORT=3306
- DB_DATABASE=laravel
- DB_USERNAME=root
- DB_PASSWORD=DATABASE_PASSWORD
- BROADCAST_DRIVER=log
- CACHE_DRIVER=file
- FILESYSTEM_DISK=minio
- QUEUE_CONNECTION=sync
- SESSION_DRIVER=file
- SESSION_LIFETIME=120
- MEMCACHED_HOST=127.0.0.1
- REDIS_HOST=127.0.0.1
- REDIS_PASSWORD=null
- REDIS_PORT=6379
- MAIL_MAILER=smtp
- MAIL_HOST=mailpit
- MAIL_PORT=1025
- MAIL_USERNAME=null
- MAIL_PASSWORD=null
- MAIL_ENCRYPTION=null
- MAIL_FROM_ADDRESS="[email protected]"
- MAIL_FROM_NAME="${APP_NAME}"
- AWS_DEFAULT_REGION=us-east-1
- AWS_USE_PATH_STYLE_ENDPOINT=false
- PUSHER_PORT=443
- PUSHER_SCHEME=https
- PUSHER_APP_CLUSTER=mt1
- VITE_APP_NAME="${APP_NAME}"
- VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
- VITE_PUSHER_HOST="${PUSHER_HOST}"
- VITE_PUSHER_PORT="${PUSHER_PORT}"
- VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
- VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
networks:
- laravel-network
volumes:
- laravel-app:/var/www/html
restart: always
nginx:
build:
context: .
dockerfile: Dockerfile.nginx
volumes:
- laravel-app:/var/www/html
ports:
- "16005:80"
networks:
- laravel-network
db:
image: mariadb
expose:
- 3306
networks:
- laravel-network
environment:
MYSQL_ROOT_PASSWORD: DATABASE_PASSWORD
MYSQL_USER: root
MYSQL_PASSWORD: DATABASE_PASSWORD
volumes:
- laravel-db:/var/lib/mysql
restart: always
phpmyadmin:
image: phpmyadmin
ports:
- "16006:80"
environment:
- PMA_HOST=db
- PMA_PORT=3306
- UPLOAD_LIMIT=50000000
networks:
- laravel-network
restart: always
Change the configuration to your needs and run the command below to start your containers:
docker compose up -d
Now you can access your Laravel app from localhost:16005 and your PhpMyAdmin from localhost:16006.
I hope this article was helpful. Please let me know of any mistakes or improvements.
BTW! Check out my free Node.js Essentials E-book here:
Feel free to contact me if you have any questions or suggestions.
SOCIAL SHARE CARD GENERATOR