├── README.md ├── docker-compose.yml ├── docker-repo ├── database │ └── docker-entrypoint-initdb.d │ │ └── README.md ├── install_laravel.sh ├── nginx │ ├── default.conf │ └── nginx.dockerfile ├── php │ ├── custom.ini │ ├── entrypoint.sh │ └── php.dockerfile └── scripts │ ├── pre-commit │ └── setup.sh └── makefile /README.md: -------------------------------------------------------------------------------- 1 | # Laravel with Docker and Make Command 2 | 3 | ### Hey everyone! 4 | 5 | I wanted to share a simple Docker setup to run Laravel without all the complexity. No need for Laravel Sail or anything like that. Plus, I wanted to make using Docker and artisan easier with the make command, so you don’t have to always be inside the Docker container to run things. 6 | 7 | ## Getting Started 8 | It’s super easy to set up. All you need to do is run these commands: 9 | 10 | bash 11 | Copy 12 | Edit 13 | make up 14 | make install-laravel 15 | That's it. You’re good to go! I’ve set everything up for a smooth Laravel project experience, including: 16 | - nginx 17 | - Postgres 18 | - Redis 19 | - PgAdmin 20 | - npm 21 | 22 | Key Features 23 | Here are a few cool things that make your life easier: 24 | 25 | No need to go inside the container for Artisan commands 26 | Just use this syntax: 27 | 28 | ```bash 29 | make artisan 30 | ``` 31 | For example: 32 | ```bash 33 | make artisan route:list 34 | ``` 35 | Composer made easy 36 | You can run Composer commands just like this: 37 | ```bash 38 | make composer 39 | ``` 40 | 41 | Automatic code formatting with Pint 42 | Clean up your code automatically with Pint. 43 | 44 | To format your code: 45 | ```bash 46 | make pint format 47 | ``` 48 | 49 | To check all files: 50 | ```bash 51 | make pint format-all 52 | ``` 53 | Testing the project 54 | Run your tests easily with: 55 | 56 | ```bash 57 | make test 58 | ``` 59 | 60 | Other Available Commands: 61 | Here’s a list of all the available make commands and what they do: 62 | 63 | ```bash 64 | make build # Run docker compose build 65 | make ps # View docker compose services 66 | make up # Start the containers 67 | make down # Stop the containers 68 | make down-volumes # Stop containers and remove volumes 69 | make restart # Restart the containers 70 | make composer # Run any composer command 71 | make tinker # Open artisan tinker 72 | make artisan # Run any artisan command 73 | make npm # Run npm commands 74 | make migration # Create a new migration 75 | make migrate # Run artisan migrate 76 | make horizon # Start Laravel Horizon 77 | make install-laravel # Download Laravel source and update .env file 78 | make pint # Format your code with Pint 79 | make test # Run tests 80 | ``` 81 | ## Final Thoughts 82 | With this setup, you can easily manage your Laravel project in Docker without the hassle. No more fiddling with Docker commands inside containers. You can handle everything from the outside using simple make commands. 83 | 84 | Enjoy, and happy coding! 85 | 86 | ## License 87 | 88 | Overall, I got a lot of these ideas from this engineer and made some improvements myself. Their work was really amazing. 89 | [Reza Khademi](https://github.com/rezakhademix) 90 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | networks: 2 | laravel: 3 | driver: bridge 4 | volumes: 5 | database-laravel: 6 | driver: local 7 | redis-laravel: 8 | driver: local 9 | pgadmin-laravel: 10 | driver: local 11 | postgresql-laravel: 12 | driver: local 13 | 14 | services: 15 | nginx: 16 | container_name: "nginx" 17 | build: 18 | context: ./docker-repo/nginx 19 | dockerfile: nginx.dockerfile 20 | args: 21 | UID: ${UID:-1000} 22 | GID: ${GID:-1000} 23 | ports: 24 | - "${FORWARD_NGINX_PORT:-80}:80" 25 | volumes: 26 | - .:/var/www/html:delegated 27 | depends_on: 28 | - php 29 | - redis 30 | - postgresql 31 | networks: 32 | - laravel 33 | 34 | php: 35 | container_name: "php" 36 | build: 37 | context: ./docker-repo/php 38 | dockerfile: php.dockerfile 39 | args: 40 | UID: ${UID:-1000} 41 | GID: ${GID:-1000} 42 | ports: 43 | - "${FORWARD_PHP_PORT:-9000}:9000" 44 | volumes: 45 | - .:/var/www/html:delegated 46 | - ./docker-repo/php/custom.ini:/usr/local/etc/php/conf.d/custom.ini 47 | networks: 48 | - laravel 49 | 50 | postgresql: 51 | image: postgres:15.4 52 | container_name: postgresql 53 | environment: 54 | POSTGRES_USER: "${DB_USERNAME:-user_db}" 55 | POSTGRES_PASSWORD: "${DB_PASSWORD:-pass_db}" 56 | POSTGRES_DB: "${DB_DATABASE:-laravel_db}" 57 | PGDATA: /data/postgres 58 | TZ: Asia/Tehran 59 | healthcheck: 60 | test: 61 | [ 62 | "CMD-SHELL", 63 | "pg_isready -d ${DB_DATABASE:-laravel_db} -U ${DB_USERNAME:-user_db}", 64 | ] 65 | interval: 5s 66 | timeout: 5s 67 | retries: 5 68 | volumes: 69 | - postgresql-laravel:/data/postgres 70 | - ./docker-repo/database/docker-entrypoint-initdb.d/:/docker-entrypoint-initdb.d 71 | ports: 72 | - "${FORWARD_MYSQL_PORT:-5432}:5432" 73 | restart: unless-stopped 74 | networks: 75 | - laravel 76 | 77 | pgadmin: 78 | image: dpage/pgadmin4 79 | container_name: pgadmin 80 | environment: 81 | PGADMIN_DEFAULT_EMAIL: "${PG_EMAIL:-admin@pgadmin.org}" 82 | PGADMIN_DEFAULT_PASSWORD: "${PG_PASSWORD:-123456}" 83 | PGADMIN_CONFIG_SERVER_MODE: "False" 84 | volumes: 85 | - pgadmin-laravel:/var/lib/pgadmin 86 | ports: 87 | - "${FORWARD_MYSQL_PORT:-8081}:80" 88 | depends_on: 89 | postgresql: 90 | condition: service_healthy 91 | restart: unless-stopped 92 | networks: 93 | - laravel 94 | # mysql: 95 | # container_name: "mysql" 96 | # image: mariadb:10.6 97 | # restart: unless-stopped 98 | # tty: true 99 | # ports: 100 | # - "${FORWARD_MYSQL_PORT:-3306}:3306" 101 | # volumes: 102 | # - database-laravel:/var/lib/mysql:delegated 103 | # - ./docker-repo/database/docker-entrypoint-initdb.d/:/docker-entrypoint-initdb.d 104 | # environment: 105 | # MYSQL_DATABASE: "${DB_DATABASE:-default_db}" 106 | # MYSQL_USER: "${DB_USERNAME:-default_user}" 107 | # MYSQL_PASSWORD: "${DB_PASSWORD:-default_password}" 108 | # MYSQL_ROOT_PASSWORD: "${DB_PASSWORD:-default_password}" 109 | # MYSQL_ALLOW_EMPTY_PASSWORD: "yes" 110 | # SERVICE_TAGS: dev 111 | # SERVICE_NAME: mysql 112 | # TZ: "${TZ:-Asia/Tehran}" 113 | # healthcheck: 114 | # test: 115 | # [ 116 | # "CMD", 117 | # "mysqladmin", 118 | # "ping", 119 | # "-p${DB_PASSWORD:-default_password}", 120 | # ] 121 | # retries: 3 122 | # timeout: 5s 123 | # networks: 124 | # - laravel 125 | 126 | # phpmyadmin: 127 | # container_name: "phpmyadmin" 128 | # image: phpmyadmin/phpmyadmin 129 | # restart: unless-stopped 130 | # ports: 131 | # - "${FORWARD_PHPMYADMIN_PORT:-8081}:80" 132 | # environment: 133 | # PMA_HOST: mysql 134 | # PMA_PASSWORD: "${DB_PASSWORD:-default_password}" 135 | # UPLOAD_LIMIT: 64M 136 | # depends_on: 137 | # - mysql 138 | # networks: 139 | # - laravel 140 | 141 | redis: 142 | container_name: "redis" 143 | image: redis:alpine 144 | restart: unless-stopped 145 | ports: 146 | - "${FORWARD_REDIS_PORT:-6379}:6379" 147 | healthcheck: 148 | test: ["CMD", "redis-cli", "ping"] 149 | retries: 3 150 | timeout: 5s 151 | volumes: 152 | - "redis-laravel:/data" 153 | networks: 154 | - laravel 155 | -------------------------------------------------------------------------------- /docker-repo/database/docker-entrypoint-initdb.d/README.md: -------------------------------------------------------------------------------- 1 | ## This is where your initial data for database locates 2 | 3 | To have an intital database data for mysql container, you must put sample.sql file into this directory otherwise you can delete directory and below line on docker-compose.yml: 4 | 5 | ``` 6 | volumes: 7 | ./database/docker-entrypoint-initdb.d/:/docker-entrypoint-initdb.d 8 | ``` 9 | -------------------------------------------------------------------------------- /docker-repo/install_laravel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Install Laravel 4 | mkdir -p src 5 | docker compose run --rm php composer create-project laravel/laravel src 6 | 7 | # Move all files including hidden ones 8 | cd src && tar cf - . | (cd .. && tar xf -) 9 | -------------------------------------------------------------------------------- /docker-repo/nginx/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | index index.php index.html; 4 | server_name _; 5 | root /var/www/html/public; 6 | 7 | location / { 8 | try_files $uri $uri/ /index.php?$query_string; 9 | } 10 | 11 | location ~ \.php$ { 12 | try_files $uri =404; 13 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 14 | fastcgi_pass php:9000; 15 | fastcgi_index index.php; 16 | include fastcgi_params; 17 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 18 | fastcgi_param PATH_INFO $fastcgi_path_info; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docker-repo/nginx/nginx.dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:stable-alpine 2 | 3 | ARG UID 4 | ARG GID 5 | 6 | ENV UID=${UID} 7 | ENV GID=${GID} 8 | 9 | # MacOS staff group's gid is 20 10 | RUN delgroup dialout 11 | 12 | RUN addgroup -g ${GID} --system laravel 13 | RUN adduser -G laravel --system -D -s /bin/sh -u ${UID} laravel 14 | RUN sed -i "s/user nginx/user laravel/g" /etc/nginx/nginx.conf 15 | 16 | ADD ./default.conf /etc/nginx/conf.d/ 17 | 18 | RUN mkdir -p /var/www/html -------------------------------------------------------------------------------- /docker-repo/php/custom.ini: -------------------------------------------------------------------------------- 1 | [PHP] 2 | memory_limit = 512M 3 | max_execution_time = 60 4 | error_reporting = E_ALL 5 | display_errors = On 6 | log_errors = On 7 | post_max_size = 50M 8 | upload_max_filesize = 50M 9 | date.timezone = UTC -------------------------------------------------------------------------------- /docker-repo/php/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "Fixing /var/run/php and /var/log permissions..." 5 | mkdir -p /var/run/php /var/log 6 | chown -R www-data:www-data /var/run/php /var/log 7 | chmod -R 777 /var/run/php /var/log 8 | 9 | echo "Fixing permissions..." 10 | chown -R www-data:www-data /var/www/storage /var/www/bootstrap/cache 11 | chmod -R 777 /var/www/storage /var/www/bootstrap/cache 12 | 13 | if [ ! -z "$WWWUSER" ] && [ ! -z "$WWWGROUP" ]; then 14 | echo "Updating www-data UID/GID to $WWWUSER:$WWWGROUP..." 15 | apk add --no-cache shadow 16 | usermod -u "$WWWUSER" www-data 17 | groupmod -g "$WWWGROUP" www-data 18 | fi 19 | 20 | echo "Switching to www-data user..." 21 | if command -v gosu > /dev/null; then 22 | exec gosu www-data "$@" 23 | elif command -v su-exec > /dev/null; then 24 | exec su-exec www-data "$@" 25 | else 26 | su - www-data -c "$@" 27 | fi 28 | -------------------------------------------------------------------------------- /docker-repo/php/php.dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.3-fpm-alpine 2 | 3 | ARG UID 4 | ARG GID 5 | 6 | ENV UID=${UID} 7 | ENV GID=${GID} 8 | 9 | RUN mkdir -p /var/www/html 10 | 11 | WORKDIR /var/www/html 12 | 13 | COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer 14 | 15 | # MacOS staff group's 16 | RUN delgroup dialout 17 | 18 | RUN addgroup -g ${GID} --system laravel 19 | RUN adduser -G laravel --system -D -s /bin/sh -u ${UID} laravel 20 | 21 | RUN apk add --no-cache su-exec \ 22 | bash \ 23 | zip \ 24 | unzip \ 25 | git \ 26 | curl \ 27 | supervisor \ 28 | tzdata \ 29 | libpng-dev \ 30 | libjpeg-turbo-dev \ 31 | freetype-dev \ 32 | postgresql-dev \ 33 | rabbitmq-c-dev \ 34 | linux-headers \ 35 | && docker-php-ext-configure gd --with-freetype --with-jpeg \ 36 | && docker-php-ext-install gd pdo pdo_mysql pdo_pgsql opcache bcmath sockets pcntl 37 | 38 | RUN apk add --no-cache ca-certificates \ 39 | autoconf \ 40 | make \ 41 | g++ \ 42 | libtool 43 | 44 | RUN pecl install redis amqp msgpack \ 45 | && docker-php-ext-enable redis amqp msgpack 46 | 47 | COPY custom.ini /usr/local/etc/php/conf.d/custom.ini 48 | 49 | RUN apk add --no-cache nodejs \ 50 | npm 51 | 52 | RUN node -v && npm -v 53 | 54 | USER laravel 55 | 56 | CMD ["php-fpm", "-y", "/usr/local/etc/php-fpm.conf", "-R"] 57 | -------------------------------------------------------------------------------- /docker-repo/scripts/pre-commit: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | echo "Check php code style and issues..." 4 | echo "Running Php cs-fixer" 5 | #./vendor/bin/pint --dirty 6 | make pint 7 | git add . 8 | echo "Done!" 9 | -------------------------------------------------------------------------------- /docker-repo/scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | cp docker-repo/scripts/pre-commit .git/hooks/pre-commit 3 | chmod +x .git/hooks/pre-commit 4 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | #!make 2 | 3 | default: help 4 | 5 | build: ## run docker compose build 6 | docker compose build 7 | 8 | ps: ## docker compose ps 9 | docker compose ps 10 | 11 | up: ## docker compose up 12 | docker compose up -d 13 | 14 | down: ## docker compose down 15 | docker compose down 16 | 17 | down-volumes: ## docker compose down with volumes 18 | docker compose down --volumes 19 | 20 | restart: ## docker compose restart 21 | docker compose restart 22 | 23 | composer: ## run composer commands 24 | docker compose run --rm -it php composer $(filter-out $@,$(MAKECMDGOALS)) 25 | %: 26 | 27 | tinker: ## artisan tinker 28 | docker compose run --rm php php artisan tinker 29 | 30 | .PHONY: artisan 31 | artisan: ## run artisan command 32 | docker compose run --rm php php artisan $(filter-out $@,$(MAKECMDGOALS)) 33 | %: 34 | @: 35 | 36 | npm: ## run npm command 37 | docker compose run --rm php npm $(filter-out $@,$(MAKECMDGOALS)) 38 | %: 39 | @: 40 | 41 | migration: ## make a new migration 42 | docker compose run --rm php php artisan make:migration $(filter-out $@,$(MAKECMDGOALS)) 43 | %: 44 | @: 45 | 46 | migrate: ## run artisan migrate 47 | docker compose run --rm php php artisan migrate 48 | 49 | horizon: ## run horizon 50 | docker compose run --rm php php artisan horizon 51 | 52 | install-laravel: ## Download source Laravel and update .env file 53 | @if [ -d "./app" ]; then \ 54 | echo "project already exists."; \ 55 | else \ 56 | chmod +x ./docker-repo/install_laravel.sh;\ 57 | ./docker-repo/install_laravel.sh;\ 58 | chown -R $(USER):$(GROUP) .;\ 59 | rm -rf src;\ 60 | fi 61 | 62 | pint-to-git: ## Download source Laravel and update .env file 63 | @if [ -d "./.git" ]; then \ 64 | chmod +x ./docker-repo/scripts/setup.sh;\ 65 | ./docker-repo/scripts/setup.sh;\ 66 | fi 67 | 68 | format: ## format codes with pint 69 | docker compose run -T --rm php ./vendor/bin/pint --dirty 70 | 71 | format-all: ## format codes with pint 72 | docker compose run -T --rm php ./vendor/bin/pint 73 | 74 | test: ## run tests 75 | docker compose run --rm php php artisan test 76 | 77 | # makefile help 78 | help: 79 | @echo "usage: make [command]" 80 | @echo "" 81 | @echo "available commands:" 82 | @sed \ 83 | -e '/^[a-zA-Z0-9_\-]*:.*##/!d' \ 84 | -e 's/:.*##\s*/:/' \ 85 | -e 's/^\(.\+\):\(.*\)/$(shell tput setaf 6)\1$(shell tput sgr0):\2/' \ 86 | $(MAKEFILE_LIST) | column -c2 -t -s : 87 | --------------------------------------------------------------------------------