Compare commits

..

2 Commits

13 changed files with 146 additions and 266 deletions

View File

@@ -1,3 +0,0 @@
*
!docker/entrypoint.sh
!docker/php.ini

View File

@@ -1,24 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[*.sh]
indent_size = 2
[Makefile]
indent_style = tab
[justfile]
indent_size = 2

View File

@@ -1,13 +0,0 @@
# Database
# config/database.php
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=app
DB_USERNAME=laravel
DB_PASSWORD=secret
# Docker
DB_ROOT_PASSWORD=secret
APP_UID=1000
APP_GID=1000

67
.gitignore vendored
View File

@@ -1,47 +1,28 @@
# Environment files
/.phpunit.cache
/bootstrap/ssr
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/resources/js/actions
/resources/js/routes
/resources/js/wayfinder
/vendor
.DS_Store
.env
.env.backup
.env.production
auth.json
Homestead.yaml
Homestead.json
# Vendor / dependencies
/vendor
/composer/
.composer/
# Laravel storage and cache
/storage/*.key
/storage/pail
/storage/framework/*
!/storage/framework/.gitignore
/storage/logs/*
!/storage/logs/.gitignore
/public/storage
# Build artifacts
/public/build
/public/hot
/public/docs
/bootstrap/cache/*
!/bootstrap/cache/.gitignore
# Testing / cache
.phpunit.result.cache
/.phpunit.cache
# Editor / IDE
/.idea
/.vscode
.phpactor.json
.scribe/
# System / logs
*.log
.DS_Store
Thumbs.db
.bash_history
# Custom
.hashes/
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
/auth.json
/.fleet
/.idea
/.nova
/.vscode
/.zed

View File

@@ -1,51 +1,34 @@
# Laravel Docker Setup
- PHP-FPM, NGINX, MySQL, phpMyAdmin (in `compose.yaml`)
- NGINX, MySQL, phpMyAdmin
## Run a container
## Создание проекта:
```bash
cp .env.example .env
# !change .env for yourself
touch .env
docker compose up -d php-fpm
docker compose exec --user www php-fpm bash
# or `just shell`
docker compose exec php-fpm bash
```
## Create a project:
**_Rewrite below for yourself:_**
*RECOMENDED:*
**The latest version** via [laravel/installer package](https://packagist.org/packages/laravel/installer)
```bash
composer global require laravel/installer && \
composer global require laravel/installer
export PATH="$HOME/.composer/vendor/bin:$PATH"
# Check options via `laravel new -h`
laravel new example-app
# copy your `.env` content to `example-app/.env`
mv example-app/* example-app/.* ./
rmdir example-app
```
*OR:*
Изменить в `.env`
**The specific version** via composer
```bash
composer create-project --prefer-dist laravel/laravel example-app ^11.0
# copy your `.env` content to `example-app/.env`
mv example-app/* example-app/.* ./
rmdir example-app
```
## Quick Actions
```bash
just
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=app
DB_USERNAME=laravel
DB_PASSWORD=secret
DB_ROOT_PASSWORD=secret
```

View File

@@ -1,5 +1,3 @@
name: laravel-setup
services:
web:
image: nginx:latest
@@ -17,42 +15,42 @@ services:
php-fpm:
build:
context: .
dockerfile: docker/Dockerfile
dockerfile: ./docker/Dockerfile
args:
UID: ${APP_UID}
GID: ${APP_GID}
UID: ${UID:-1000}
GID: ${GID:-1000}
env_file:
- .env
volumes:
- ./:/var/www
- ./docker/docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh
depends_on:
mysql:
condition: service_started
mysql:
image: mysql:8.0
ports:
- "127.0.0.1:${DB_PORT:-3306}:3306"
- "${DB_PORT:-3306}:3306"
environment:
- MYSQL_DATABASE=${DB_DATABASE}
- MYSQL_USER=${DB_USERNAME}
- MYSQL_PASSWORD=${DB_PASSWORD}
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
volumes:
- mysql-data-development:/var/lib/mysql
- mysql-data:/var/lib/mysql
phpmyadmin:
image: phpmyadmin:latest
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
- "8080:80"
environment:
- PMA_HOST=mysql
- PMA_USER=root
- PMA_PASSWORD=${DB_ROOT_PASSWORD}
- PMA_PORT=${DB_PORT:-3306}
- UPLOAD_LIMIT=100M
depends_on:
mysql:
condition: service_started
- mysql
volumes:
mysql-data-development:
mysql-data:

View File

@@ -1,41 +1,33 @@
FROM mysql:8.0 AS mysql
FROM php:8.3-fpm
COPY --from=mysql /usr/bin/mysql /usr/bin/mysql
COPY --from=mysql /usr/bin/mysqldump /usr/bin/mysqldump
RUN apt-get update && apt-get install -y --no-install-recommends \
libonig-dev libicu-dev \
gosu netcat-traditional \
&& docker-php-ext-install pdo_mysql mbstring intl \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
ARG UID
ARG GID
# Create a new user with the specified UID and GID, reusing an existing group if GID exists
RUN if getent group ${GID}; then \
group_name=$(getent group ${GID} | cut -d: -f1); \
useradd -m -u ${UID} -g ${GID} -s /bin/bash www; \
else \
groupadd -g ${GID} www && \
useradd -m -u ${UID} -g www -s /bin/bash www; \
group_name=www; \
fi
RUN apt-get update && apt-get install -y \
netcat-traditional \
libpng-dev \
libonig-dev \
libxml2-dev \
libzip-dev \
zip \
unzip \
git \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Update php-fpm to use the new user and group
RUN sed -i "s/user = www-data/user = www/g" /usr/local/etc/php-fpm.d/www.conf && \
sed -i "s/group = www-data/group = $group_name/g" /usr/local/etc/php-fpm.d/www.conf
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
COPY --chmod=644 ./docker/php.ini /usr/local/etc/php/conf.d/laravel.ini
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY ./docker/entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh
COPY ./docker/php-fpm.conf /usr/local/etc/php-fpm.d/zz-docker.conf
COPY ./docker/docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
RUN groupadd -g $GID laravel && useradd -u $UID -g $GID -m laravel
USER laravel
WORKDIR /var/www
EXPOSE 9000
ENTRYPOINT ["entrypoint.sh"]
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["php-fpm"]

63
docker/docker-entrypoint.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/bin/sh
set -e
cd /var/www
echo ">> Running in ${APP_ENV:-unknown} mode"
if [ -f "artisan" ]; then
chown -R laravel:laravel /var/www/storage /var/www/bootstrap/cache
chmod -R 775 /var/www/storage /var/www/bootstrap/cache
if [ ! -d "vendor" ]; then
echo ">> Installing composer dependencies..."
if [ "$APP_ENV" = "production" ]; then
composer install --no-dev --optimize-autoloader
else
composer install --optimize-autoloader
fi
else
echo ">> Vendor directory exists, skipping installation"
fi
if [ -f ".env" ] && grep -q '^APP_KEY=$' .env; then
echo ">> APP_KEY is missing. Generating application key..."
php artisan key:generate --ansi
fi
echo ">> Waiting for MySQL to be ready..."
while ! nc -z mysql 3306; do
sleep 1
done
echo ">> MySQL is ready!"
echo ">> Running migrations..."
php artisan migrate --force || true
if [ ! -L "public/storage" ] && [ -d "storage/app/public" ]; then
echo ">> Creating storage link..."
php artisan storage:link
else
echo ">> Storage link already exists or storage directory missing"
fi
if [ "$APP_ENV" = "local" ]; then
echo ">> Running seeders..."
php artisan db:seed --force || true
if composer show knuckleswtf/scribe > /dev/null 2>&1; then
echo ">> Generating API documentation..."
php artisan scribe:generate --no-interaction || echo ">> Documentation generation failed, continuing..."
else
echo ">> Scribe not installed, skipping documentation generation"
fi
fi
if [ "$APP_ENV" = "production" ]; then
php artisan optimize
fi
else
echo ">> Not a Laravel project"
fi
exec "$@"

View File

@@ -1,62 +0,0 @@
#!/bin/sh
set -e
echo ">> Running dev setup..."
# Only for Laravel project
if [ ! -f "artisan" ]; then
echo ">> Not a Laravel project"
exec "$@"
fi
gosu www mkdir -p .hashes
if [ ! -f "vendor/autoload.php" ] || [ ! -f .hashes/.composer-hash ] || ! sha1sum -c .hashes/.composer-hash; then
echo ">> composer.json or composer.lock changed, installing dependencies..."
gosu www composer install --optimize-autoloader --no-interaction
gosu www sha1sum composer.json composer.lock > .hashes/.composer-hash
chown www: .hashes/.composer-hash
else
echo ">> Composer dependencies up to date (hash match), skipping install."
fi
if [ -f ".env" ] && grep -q '^APP_KEY=$' .env; then
echo ">> Generating application key..."
gosu www php artisan key:generate --ansi
fi
echo ">> Waiting for MySQL..."
while ! nc -z mysql 3306; do sleep 1; done
echo ">> Running migrations..."
gosu www php artisan migrate --force
if [ ! -L "public/storage" ] && [ -d "storage/app/public" ]; then
echo ">> Creating storage link..."
gosu www php artisan storage:link
fi
echo ">> Running seeders..."
gosu www php artisan db:seed --force
if composer show knuckleswtf/scribe >/dev/null 2>&1; then
# Define all directories/files Scribe cares about
SCRIBE_SOURCES="config/scribe.php routes/ app/Http/Controllers/ app/Http/Requests/ app/Models/"
# Create combined hash of all .php files in those paths
CURRENT_HASH=$(find $SCRIBE_SOURCES -type f -name "*.php" -exec sha1sum {} + | sha1sum)
if [ ! -f .hashes/.scribe-hash ] || [ "$CURRENT_HASH" != "$(cat .hashes/.scribe-hash)" ]; then
echo ">> Generating API documentation..."
gosu www php artisan scribe:generate --no-interaction \
|| echo ">> Warning: Scribe generation failed, continuing..."
echo "$CURRENT_HASH" > .hashes/.scribe-hash
chown www: .hashes/.scribe-hash
else
echo ">> API docs up to date, skipping Scribe generation."
fi
else
echo ">> Scribe not installed, skipping API docs generation"
fi
exec "$@"

View File

@@ -1,6 +1,5 @@
server {
listen 80;
client_max_body_size 20M;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;

12
docker/php-fpm.conf Normal file
View File

@@ -0,0 +1,12 @@
[global]
daemonize = no
[www]
user = laravel
group = laravel
listen = 9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

View File

@@ -1,2 +0,0 @@
post_max_size = 20M
upload_max_filesize = 20M

View File

@@ -1,44 +0,0 @@
set dotenv-load
set shell := ["bash", "-eu", "-o", "pipefail", "-c"]
APP_UID := env("APP_UID", "1000")
APP_GID := env("APP_GID", "1000")
IMAGE_NAME := "laravel-setup-php-fpm"
IMAGE_TAG := "latest"
IMAGE := IMAGE_NAME + ":" + IMAGE_TAG
# Show available recipes
default:
@just --list
# Build Docker image
build:
docker build -f docker/Dockerfile \
--build-arg UID={{APP_UID}} \
--build-arg GID={{APP_GID}} \
-t {{IMAGE}} .
# Open shell in PHP-FPM container
shell:
docker compose exec --user www php-fpm bash
# Generate API documentation
docs *args:
docker compose exec --user www php-fpm php artisan scribe:generate {{ args }}
# Regenerate DB and docs
docs-fresh:
just db && just docs --force
# Reset database with fresh migration and seeding
db:
docker compose exec --user www php-fpm php artisan migrate:fresh --seed
# Run tests
test:
docker compose exec --user www php-fpm php artisan test
# Run Pint
lint:
docker compose exec --user www php-fpm php ./vendor/bin/pint