From 842b5b25a1c7fd0b15e0f8eccc3440acbc3777ac Mon Sep 17 00:00:00 2001 From: Chicory Date: Thu, 21 Aug 2025 11:35:28 +0300 Subject: [PATCH] PHP 8.4 environment --- .editorconfig | 12 ++++++ .gitignore | 5 +++ README.md | 78 ++++++++++++++++++++++++++++++++++++++ composer.json | 13 +++++++ docker/.env | 4 ++ docker/conf/launch.json | 15 ++++++++ docker/conf/nginx.conf | 57 ++++++++++++++++++++++++++++ docker/conf/xdebug.ini | 7 ++++ docker/docker-compose.yaml | 15 ++++++++ docker/dockerfile | 77 +++++++++++++++++++++++++++++++++++++ docker/entrypoint.sh | 8 ++++ makefile | 48 +++++++++++++++++++++++ public/index.php | 3 ++ 13 files changed, 342 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 README.md create mode 100644 composer.json create mode 100644 docker/.env create mode 100644 docker/conf/launch.json create mode 100644 docker/conf/nginx.conf create mode 100644 docker/conf/xdebug.ini create mode 100644 docker/docker-compose.yaml create mode 100644 docker/dockerfile create mode 100644 docker/entrypoint.sh create mode 100644 makefile create mode 100644 public/index.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2e7acaf --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fef825e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +composer.lock +vendor +.idea +.vscode + diff --git a/README.md b/README.md new file mode 100644 index 0000000..281dcf7 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +Docker PHP environment +====================== + +A lightweight and developer-friendly Docker environment for PHP projects. + +What you get out of the box: +* PHP 8.4 with popular extensions used in most frameworks. +* Nginx web server tuned for PHP-FPM. +* Handy developer tools (Git, Make, cURL). +* One-line commands to manage the environment. +* Instant Xdebug setup with VSCode integration. + +Installed packages +------------------ +* PHP 8.4 +* nginx +* curl +* make +* git + +Installed PHP extensions +------------------------ +* pdo_pgsql +* bcmath +* curl +* exif +* zip +* bz2 +* gd + +Configuration +------------- +Set up environment variables in `.env`: +```shell +nano ./docker/.env +``` + +Commands +-------- +Show available commands: +```shell +make help +``` + +Run environment (available on `APP_PORT`): +```shell +make up +``` + +Stop environment: +```shell +make down +``` + +Restart environment: +```shell +make restart +``` + +Publish VSCode Xdebug config: +```shell +make vscode-xdebug +``` + +Build Docker image: +```shell +make build +``` + +Publish image: +```shell +make push +``` + +Cleanup: +```shell +make clear +``` diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4e9870f --- /dev/null +++ b/composer.json @@ -0,0 +1,13 @@ +{ + "name": "username/php-app", + "description": "PHP App template", + "type": "project", + "license": "CC0-1.0", + "minimum-stability": "stable", + "prefer-stable": true, + "require": { + "php": ">=8.4", + "ext-ctype": "*", + "ext-iconv": "*" + } +} diff --git a/docker/.env b/docker/.env new file mode 100644 index 0000000..ff2de28 --- /dev/null +++ b/docker/.env @@ -0,0 +1,4 @@ +UID=1000 +GID=1000 +APP_NAME = app +APP_PORT = 8080 diff --git a/docker/conf/launch.json b/docker/conf/launch.json new file mode 100644 index 0000000..057e8d3 --- /dev/null +++ b/docker/conf/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003, + "stopOnEntry": true, + "pathMappings": { + "/app": "${workspaceRoot}" + } + } + ] +} diff --git a/docker/conf/nginx.conf b/docker/conf/nginx.conf new file mode 100644 index 0000000..031e449 --- /dev/null +++ b/docker/conf/nginx.conf @@ -0,0 +1,57 @@ +pid /tmp/nginx.pid; +worker_processes auto; +error_log /dev/stderr warn; + +events { + worker_connections 2048; + multi_accept on; +} + +http { + include /etc/nginx/mime.types; + + server_tokens off; + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 15; + types_hash_max_size 2048; + client_max_body_size 20M; + + access_log /dev/stdout; + error_log /dev/stderr; + gzip on; + + upstream php-upstream { + server 127.0.0.1:9000; + } + + server { + listen 80; + listen [::]:80; + + root /app/public; + index index.php; + + location / { + try_files $uri /index.php$is_args$args; + } + + location ~ ^/index\.php(/|$) { + include fastcgi_params; + + fastcgi_pass php-upstream; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + + fastcgi_buffers 16 16k; + fastcgi_buffer_size 32k; + } + + location ~ \.php$ { + return 404; + } + } +} diff --git a/docker/conf/xdebug.ini b/docker/conf/xdebug.ini new file mode 100644 index 0000000..6844da5 --- /dev/null +++ b/docker/conf/xdebug.ini @@ -0,0 +1,7 @@ +xdebug.mode=debug +xdebug.discover_client_host=1 +xdebug.start_with_request=yes +xdebug.idekey=vsc +xdebug.client_host=host.docker.internal +xdebug.log_level=0 +xdebug.client_port=9003 diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml new file mode 100644 index 0000000..63710ee --- /dev/null +++ b/docker/docker-compose.yaml @@ -0,0 +1,15 @@ +services: + app: + container_name: ${APP_NAME}-app + build: + context: ../ + dockerfile: docker/dockerfile + args: + UID: ${UID} + GID: ${GID} + DEBUG: 'true' + BUILD_MODE: 'dev' + volumes: + - ../:/app + ports: + - ${APP_PORT}:80 diff --git a/docker/dockerfile b/docker/dockerfile new file mode 100644 index 0000000..a5f80a8 --- /dev/null +++ b/docker/dockerfile @@ -0,0 +1,77 @@ +FROM php:8.4-fpm-alpine3.21 + +ARG UID=1000 +ARG GID=1000 +ARG DEBUG=false +ARG BUILD_MODE=prod + +# Custom prompt +ENV PS1="\033[01;32mapp\033[00m:\033[01;34m\w\033[00m\$ \033[37m" + +# Install packages +RUN apk add --update --no-cache \ + linux-headers \ + curl \ + curl-dev \ + git \ + build-base \ + libpq-dev \ + libpng-dev \ + libzip-dev \ + zlib-dev \ + oniguruma-dev \ + autoconf \ + nginx \ + bash \ + shadow \ + make + +# Install PHP extensions +RUN docker-php-ext-install \ + pdo_pgsql \ + bcmath \ + curl \ + exif \ + zip \ + bz2 \ + gd + +# Configure non-root user +RUN groupmod -o -g ${GID} www-data && \ + usermod -o -u ${UID} -g www-data www-data + +# Copy application +WORKDIR /app +RUN chown www-data:www-data /app +COPY --chown=www-data:www-data ./ /app + +# Configure Xdebug +RUN if [ ${DEBUG} = "true" ]; \ + then \ + pecl install xdebug && docker-php-ext-enable xdebug; \ + fi; +COPY ./docker/conf/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini + +# Install composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# Install php dependencies +RUN if [ ${BUILD_MODE} = "prod" ]; \ + then \ + composer install --no-dev --no-interaction --no-progress --no-scripts --optimize-autoloader; \ + chown -R www-data:www-data /app/vendor/; \ + fi; + +# Configure nginx +RUN touch /var/lib/nginx/logs/error.log && chown www-data:www-data /var/lib/nginx/logs/error.log +RUN chown -Rf www-data:www-data /var/lib/nginx /run +COPY ./docker/conf/nginx.conf /etc/nginx/ + +COPY ./docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +USER www-data + +EXPOSE 80 + +CMD ["/entrypoint.sh"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..7f3771f --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +echo "Starting php-fpm..." +php-fpm -D + +echo "Starting nginx..." +exec nginx -g "daemon off;" diff --git a/makefile b/makefile new file mode 100644 index 0000000..4d7d60d --- /dev/null +++ b/makefile @@ -0,0 +1,48 @@ +.DEFAULT_GOAL := help + +UID = $(shell id -u) +GID = $(shell id -g) + +DOCKER_HUB_USER ?= username +IMAGE_NAME ?= php +IMAGE_TAG ?= 8.4 + +BUILD_TAG ?= $(DOCKER_HUB_USER)/$(IMAGE_NAME):$(IMAGE_TAG) +CONTAINER_NAME ?= $(DOCKER_HUB_USER)-$(IMAGE_NAME)-$(IMAGE_TAG) + +DOCKER_COMPOSE = docker-compose -f docker/docker-compose.yaml + +help: ## Show this help. + @awk 'BEGIN {FS = ":.*##";} /^[a-zA-Z]/ && !/\?=/ {printf " \033[32m%-15s\033[90m %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +install: ## Install docker-compose. + @make up + @${DOCKER_COMPOSE} exec app bash -c "composer install" + +up: ## Start dev environment. + @${DOCKER_COMPOSE} up -d --build + +down: ## Stop dev environment. + @${DOCKER_COMPOSE} down + +restart: ## Restart dev environment. + @${DOCKER_COMPOSE} restart + +exec: ## Container shell + @${DOCKER_COMPOSE} exec app bash + +build: clear ## Build image. + @docker build --tag="$(BUILD_TAG)" --build-arg UID=$(UID) --build-arg GID=$(GID) -f docker/dockerfile . + +push: build ## Publish image + @docker logout + @docker login --username=$(DOCKERHUB_USER) + @docker push $(BUILD_TAG) + +clear: ## Cleanup. + @docker rmi -f $(BUILD_TAG) + @docker rm -vf $(CONTAINER_NAME) + +vscode-xdebug: ## Publish vscode xdebug config. + @mkdir -p .vscode + @cp docker/conf/launch.json .vscode/launch.json diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..83f1549 --- /dev/null +++ b/public/index.php @@ -0,0 +1,3 @@ +