This repository represents a rich template for deploying development environments using dockers. Where we build a separated architecture of backend and frontend projects, with all the services associated to them ready to run. This is very convenient, for example, in application environments where the backend serves an API and the frontend consumes it.
We are using Docker Compose
with NGINX
, Node
, PHP-FPM
, MariaDB
and phpMyAdmin
services. Laravel
is being used for the backend side and Vue + Vite
for the frontend. Each service and application source is containerized using dockers.
Note: Initially this repository is intended to be used as development containers, a new way of using Dockers containers with development environments installed inside them, and not in your main system, in a service infrastructure context very similar to the existing one in productions environments.
This project has been mainly created for Unix (Linux/MacOS). Perhaps it could work on Windows if you use WSL (Windows Subsystem for Linux)
All requisites should be available for your distribution. The most important are :
- WSL 2 (Windows users)
- Git
- Docker
- Docker Compose
- Visual Studio Code (You can use whatever IDE allows you to work inside containers)
Check if docker-compose
is already installed by entering the following command:
which docker-compose
Check Docker Compose compatibility :
This services use the following ports.
Server | Port |
---|---|
MariaDB | 3306 |
PHPMyAdmin | 8080 |
Nginx | 8000 |
Service | URL | Observations |
---|---|---|
Frontend (Vue+Vite) | http://localhost:8000 | |
Backend (Laravel) | http://localhost:8000/api/ | Backend API Route served from Artisan. (Dev) |
Backend (Laravel) | http://localhost:8001/api/ | Backend served from FPM. (Production) |
phpMyAdmin | http://localhost:8080 |
- Nginx is being used to do reverse proxy to route backend, frontend and phpMyAdmin services.
- The backend is configured to be served in the development environment from both Artisan and FPM. This is to check that everything works correctly and to be able to test in the development environment. In the
.devcontainer/backend/docker-entrypoint.sh
path you can configure how to serve the application during development.
Here are some summary guidelines for using this repository to start a new project or include your Laravel and Vue projects in this architecture.
git clone https://github.com/jraicr/docker-lemp-laravel-vue.git myProject
After cloning you can change or remove the remote origin from this repository and set up your own for the project. How to use git is beyond the scope of this document.
Related links
First you must add to your .bashrc
or .zshrc
file the following variable exports:
- Open
.bashrc
or.zshrc
with a text editor like nano:
cd ~
nano .bashrc
- Write the following lines at the end of the file:
export UID="$UID"
export USERNAME="$USER"
export PWD="$PWD"
Secondly you should be editing the docker compose environment file to setup the services:
-
Copy
.devcontainer/.example.env
to.devcontainer/.env
Here you will configure everything you need to make the container services work correctly: -
You must configure
PROJECT_NAME
variable. -
You can change
NGINX_HOST
variable, it is set tolocalhost
by default. If you need to change NGINX configuration you are able to do it from the file.devcontainer/webserver/config/nginx/conf.d/default.conf.template.nginx
-
Change database connection root and user passwords within the variables
CONFIG_MARIADB_ROOT_PASSWORD
andCONFIG_MARIADB_PASSWORD
.- You can also set the username variable
CONFIG_MARIADB_USER
from MariaDB, wich user is being used in Laravel by default.
- You can also set the username variable
-
-
Configure Laravel environment variables (more info)
ℹ️ See configuration for more details.
- To generate a new Laravel project uses this command from the project root:
sh -c bash_tools/scripts/generate_first_time_backend.sh
- To generate a new Vue+Vite project uses this command from the project root:
sh -c bash_tools/scripts/generate_first_time_frontend.sh
ℹ️ See frontend & backend projects for more details if you need to includes existing projects.
- Compose up command:
docker compose -f ".devcontainer/docker-compose.yml" up -d --build
- Compose down command:
docker compose -f ".devcontainer/docker-compose.yml" down
If you are using VS Code as your main IDE, alternatively you can open the project folder and do a right click on docker-compose file in order to manage it. This require to have installed Docker VSCode extension. After composing up the containers you should be able to connect to web services in your web browser.
To start working inside a container from VS Code
you will need Remote Development extension pack (if you are in windows you will need WSL 2) you can press F1 and type Attach to running container
then select the frontend or backend container to start working inside it. You can also do it from the Dockers view in VS Code and doing a right click on the container you are interested to work in and select Attach Visual Studio Code
.
ℹ️ See developing inside a container for more details.
In the following sections we will discuss the architecture configurations in more depth.
First of all we need to make sure that we have some environment variables available on our own computer. To do this follow the steps below.
- Open .bashrc or .zshrc with a text editor like nano:
cd ~
nano .bashrc
- Write the following lines at the end of the file:
export UID="$UID"
export USERNAME="$USER"
export PWD="$PWD"
The env variables file used for docker-compose and containers are found in .devcontainer/.env
here you can configure all the services. In case you want to change any port you are recommended to only set the external ports where you are going to connect to the services.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# DOCKER COMPOSE ENV VARS #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
### DOCKER-COMPOSE ENV ###
# ℹ https://docs.docker.com/compose/environment-variables/#the-env-file
PROJECT_NAME=ProjectName # ✏️ Writes here your project name
COMPOSE_PROJECT_NAME=${PROJECT_NAME}_devcontainer
### NGINX Webserver ###
# Port to connect to Frontend and Backend services routed by nginx
FRONTEND_BACKEND_EXTERNAL_PORT=8000 # (http://localhost:8000)
BACKEND_FPM_EXTERNAL_PORT=8001 # This is the backend served with FPM (http://localhost:8001)
### MariaDB ###
# Port to connect to the database server
MARIADB_EXTERNAL_PORT=3306
### PHP MY ADMIN ###
# Port to connect to phpMyAdmin
PHPMYADMIN_EXTERNAL_PORT=8080 # (http://localhost:8080)
# It is recommended to not touch internal ports in the following docker configuration
### Backend ###
# Port used by the backend container for internal docker network
BACKEND_EXPOSE_PORT=8080
BACKEND_FPM_EXPOSE_PORT=9001
### Frontend ###
# Port used by the frontend container for internal docker network
FRONTEND_EXPOSE_PORT=8080
NODE_DEVELOPMENT=development
Note: Be sure to change the name of the project in the
.devcontainer/.env
file. Many docker parameters are built from this name. Also, the source code of laravel and vue projects will be located in named folders:projectName_backend
andprojectName_frontend
In the nexts sections we are going to configure variables that will be passed to their respectives containers using their own .env file located in:
.devcontainer/backend/.backend.env
.devcontainer/frontend/.frontend.env
devcontainer/mariadb/.mariadb.env
.devcontainer/webserver/.webserver.env
You won't need to edit any of this files unless you wish to expose other configuration options that are not provided by default. Just continue editing the .devcontainer/.env
file.
The most important variable to take into account is NGINX_HOST
, it is set to localhost by default.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# NGINX CONTAINER ENV VARS #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Environment Variables for NGINX Docker Container
CONFIG_NGINX_HOST=localhost # ✏️ You can edit this (e.g.: NGINX_HOST=rai.ddns.net)
CONFIG_FRONTEND_CONNECTION_PORT=${FRONTEND_EXPOSE_PORT}
CONFIG_BACKEND_CONNECTION_PORT=${BACKEND_EXPOSE_PORT}
CONFIG_BACKEND_FPM_CONNECTION_PORT=${BACKEND_FPM_EXPOSE_PORT}
Here you can change the root and user passwords. By default MARIADB_USER
is set to dev
but you can change it for whatever username you want.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# DB CONTAINER ENV VARS #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Environment Variables for MariaDB Docker Container
# More info: https://mariadb.com/kb/en/mariadb-docker-environment-variables/
CONFIG_MARIADB_CONNECTION=mysql
CONFIG_MARIADB_HOST=${PROJECT_NAME}_mariadb
CONFIG_MARIADB_ROOT_USER=root
CONFIG_MARIADB_ROOT_PASSWORD=qwerty # ✏️ CHANGE THIS PASSWORD
CONFIG_MARIADB_USER=dev
CONFIG_MARIADB_PASSWORD=dev # ✏️ CHANGE THIS PASSWORD
CONFIG_MARIADB_ROOT_HOST=172.0.0.0/255.0.0.0
CONFIG_MARIADB_DATABASE=${PROJECT_NAME}_bd
The database will be created using PROJECT_NAME
as prefix.
Show backend configuration section
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# BACKEND CONTAINER ENV VARS #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
### Environment Variables for Backend container ###
### Docker Entrypoint Configuration ###
CONFIG_BACKEND_LISTENING_PORT=${BACKEND_EXPOSE_PORT} # Serves Laravel project using artisan in this port
CONFIG_BACKEND_FPM_LISTENING_PORT=${BACKEND_FPM_EXPOSE_PORT} # Serves Laravel project using FPM in this port
### PHP OPcache Configuration
CONFIG_PHP_OPCACHE_ENABLE=1
CONFIG_PHP_OPCACHE_MAX_ACCELERATED_FILES="10000"
CONFIG_PHP_OPCACHE_MEMORY_CONSUMPTION="256M"
CONFIG_PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10"
# ❌ USE VALUE "1" ONLY IN DEVELOPMENT ENVIRONMENTS ❌
# This allows us to make changes to our code. If you’re using a Docker volume,
# it means that OPcache will respect file timestamps and your changes will reflect immediately.
# In a production environment that’s not ideal and we are losing the cache features from OPcache.
CONFIG_PHP_OPCACHE_VALIDATE_TIMESTAMPS="1"
### Laravel Configuration ###
# More info: https://laravel.com/docs/9.x/configuration
LARAVEL_APP_NAME=${PROJECT_NAME}_API
LARAVEL_APP_ENV=local
LARAVEL_APP_DEBUG=true
LARAVEL_APP_URL=http://${CONFIG_NGINX_HOST}
LARAVEL_LOG_CHANNEL=stack
LARAVEL_LOG_DEPRECATIONS_CHANNEL=null
LARAVEL_LOG_LEVEL=debug
LARAVEL_DB_CONNECTION=mysql
LARAVEL_DB_HOST=${CONFIG_MARIADB_HOST}
LARAVEL_DB_PORT=3306
LARAVEL_DB_DATABASE=${CONFIG_MARIADB_DATABASE}
LARAVEL_DB_USERNAME=${CONFIG_MARIADB_USER}
LARAVEL_DB_PASSWORD=${CONFIG_MARIADB_PASSWORD}
LARAVEL_BROADCAST_DRIVER=log
LARAVEL_CACHE_DRIVER=file
LARAVEL_FILESYSTEM_DISK=local
LARAVEL_QUEUE_CONNECTION=sync
LARAVEL_SESSION_DRIVER=file
LARAVEL_SESSION_LIFETIME=120
LARAVEL_MEMCACHED_HOST=127.0.0.1
LARAVEL_REDIS_HOST=127.0.0.1
LARAVEL_REDIS_PASSWORD=null
LARAVEL_REDIS_PORT=6379
LARAVEL_MAIL_MAILER=smtp
LARAVEL_MAIL_HOST=mailhog
LARAVEL_MAIL_PORT=1025
LARAVEL_MAIL_USERNAME=null
LARAVEL_MAIL_PASSWORD=null
LARAVEL_MAIL_ENCRYPTION=null
LARAVEL_MAIL_FROM_ADDRESS="[email protected]"
LARAVEL_MAIL_FROM_NAME="${LARAVEL_APP_NAME}"
LARAVEL_AWS_ACCESS_KEY_ID=
LARAVEL_AWS_SECRET_ACCESS_KEY=
LARAVEL_AWS_DEFAULT_REGION=us-east-1
LARAVEL_AWS_BUCKET=
LARAVEL_AWS_USE_PATH_STYLE_ENDPOINT=false
LARAVEL_PUSHER_APP_ID=
LARAVEL_PUSHER_APP_KEY=
LARAVEL_PUSHER_APP_SECRET=
LARAVEL_PUSHER_HOST=
LARAVEL_PUSHER_PORT=443
LARAVEL_PUSHER_SCHEME=https
LARAVEL_PUSHER_APP_CLUSTER=mt1
LARAVEL_VITE_PUSHER_APP_KEY="${LARAVEL_PUSHER_APP_KEY}"
LARAVEL_VITE_PUSHER_HOST="${LARAVEL_PUSHER_HOST}"
LARAVEL_VITE_PUSHER_PORT="${LARAVEL_PUSHER_PORT}"
LARAVEL_VITE_PUSHER_SCHEME="${LARAVEL_PUSHER_SCHEME}"
LARAVEL_VITE_PUSHER_APP_CLUSTER="${LARAVEL_PUSHER_APP_CLUSTER}"
### OCTANE Configuration ###
LARAVEL_OCTANE_SERVER=swoole
In this block you can configure the environment variables needed by the backend container and used by Laravel. The latter will ignore the values in the original .env
file, located in the Laravel source code folder, if we setup the same variable name in our file. Besides this, we expose variables to config the php OPcache extension
.
Note: The APP key that Laravel generates with artisan will not be configured in this file and Laravel will read it from its own .env. We do this to save us configuration steps, when Laravel already fills in this data for us.
- More information about Laravel environment configuration
- More information about OPcache environment configuration
For the moment being it is not needed to pay any attention for configuration in this section.
The configuration file is located in .devcontainer/webserver/config/etc/nginx/conf.d/default.conf.template.nginx
. If you need to change some NGINX
configuration you can do it here.
You can find the php configuration files in the directory devcontainer/backend/config/etc/php/conf.d
In this path you can configure the php.ini
file, as well as the port to which XDebug
connects, among other options. Some of the OPcache
config values are taken from the environment variables configured in .devcontainer/.env
The configuration files in the path .devcontainer/backend/config/etc/php-fpm.d/
are for PHP's FPM service.
You are free to add more configuration files to PHP by mounting a new volume - inside the backend container - in the docker-compose.yml
file. You can see the current ones as an example:
backend:
(...)
volumes:
- ../${PROJECT_NAME}_backend:/app # Laravel Project
- ./backend/config/etc/php/conf.d/php.ini-development.ini:/usr/local/etc/php/php.ini # PHP Config
- ./backend/config/etc/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf # PHP-FPM Config
- ./backend/config/etc/php-fpm.d/zz-docker.conf:/usr/local/etc/php-fpm.d/zz-docker.conf # PHP-FPM Config
- ./backend/config/etc/php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini # PHP XDebug Config
- ./backend/config/etc/php/conf.d/opcache.ini:/usr/local/etc/php/conf.d/opcache.ini # PHP OPcache config
- ./backend/docker-entrypoint.sh:/docker-entrypoint.sh # Backend Docker entrypoint script
(...)
The .devcontainer/backend/docker-entrypoint.sh
file is executed as soon as the backend container is raised. By default the Laravel application is served using Artisan and FPM at the same time, later both are routed with nginx. You can edit the file to decide how to serve the application during development.
Remember that in production environments it is desirable to serve the Laravel application with FPM or other options such as Laravel Octane with Swoole.
The user root
from the database can only be accessed from the same networks that belong to the docker network. It is well configured so you dont need to worry even if you are running WSL 2 on Windows, you will be able to access it from your Windows host using your favourite mariaDB client
or using phpMyAdmin
.
phpMyAdmin
is useful to manage our database through the web browser. By default you can access it only from localhost.
Each time the mariaDB container
is up it will be executing automatically the file in .devcontainer/mariadb/config/db/docker-entrypoint-initdb.d/db_init.sql
. For the moment it is used in the starting point to create phpMyAdmin configuration tables and to assign privileges to them to the user configured in the variable MARIADB_USER
from the mariaDB environment variables container file .mariadb.env
. If you think this tables should be created in another moment or context, you are free to edit this if you know what you are doing.
Note: It is strongly recommended to not deploy phpMyAdmin in production environments. It is useful to work only inside development environments.
Over time I will be adding to this project other docker compose options, more suitable for deployment in production environments. Feel free to adapt compose for production environments but be aware of security warnings, such as avoiding phpMyAdmin deployments.
The images used in frontend and backend containers are used to work with Laravel and Vue + Vite, although the services of both projects coexist on the same nginx proxy server, they are projects that should be in completely different repositories.
Before composing up the containers it is important to have ready the folders with both projects, since frontend and backend containers will be mounting this folders as volumes.
You can generate new Laravel and Vue projects using the bash scripts .bash_tools/scripts/generate_first_time_backend.sh
and .bash_tools/scripts/generate_first_time_frontend.sh
. They are using docker images to generate the full projects.
- To generate a new Laravel project uses this command from the project root:
sh -c bash_tools/scripts/generate_first_time_backend.sh
- To generate a new Vue+Vite project uses this command from the project root:
sh -c bash_tools/scripts/generate_first_time_frontend.sh
It is important to take into account that vite config file in .devcontainer/config/vite.config.template.js
is mounted in the frontend container using volumes. When frontend container starts, it copy the file to projectName_frontend/vite.config.js
using envsubst
to converts environment variables to the data they are pointing. So if you are going to change it you must restart the container for them to take effect.
How to work with Laravel or Vue is out of scope of this document.
You can add your projects creating git submodules that points to them. Remember that folders name must be ${PROJECT_NAME}_backend
and ${PROJECT_NAME}_frontend
. As said before, PROJECT_NAME
can be set in ./devcontainer/.env
.
Write this commands to create git submodules from the project root:
git submodule add https://github.com/user/frontAPP ProjectName_frontend
git submodule add https://github.com/user/backAPI ProjectName_backend
As the repositories where these projects are located do not include the dependency files they need (or at least they shouldn't), we have prepared some scripts that will help you with this task.
- Run this command from the root of the project to install the backend dependencies:
sh -c bash_tools/scripts/install_dependencies_backend.sh
- Run this command from the root of the project to install the frontend dependencies:
sh -c bash_tools/scripts/install_dependencies_frontend.sh
In the case of the backend it will also copy the Laravel configuration file .env.example
to .env
and then generate an API key for the application.
Note: Do not run these scripts if your projects were previously generated with
generate_first_first_time_backend.sh
orgenerate_first_time_frontend.sh
as these are generated with all the dependencies they need.
Monorepositories: I think it is possible to work in a monorepo using this setup, instead of using git submodules, since each project is isolated in a folder and with its own docker-based environment tools. So, to do this you just put in the project the source code in the frontend and backend folders and let them coexist in a single git repository. It is up to you to decide how to manage the workflow with git and your projects.
Feel free to contribute to this project with any changes. Make a fork of the repository and clone it on your computer, make changes as you see fit and create a pull request.