diff --git a/.env b/.env index 1138e9315..f974f425f 100644 --- a/.env +++ b/.env @@ -1,20 +1,55 @@ -#!/usr/bin/env bash +# Development environment configuration -# See https://docs.docker.com/compose/environment-variables/#the-env-file +# Application configuration +APP_NAME=docker_nginx_php_mysql +APP_WORKSPACE=default +APP_DIR=app +APP_PUBLIC_DIR=app/public -# Nginx +# Common settings NGINX_HOST=localhost +NGINX_PORT=8000 -# PHP +# Nginx SSL Certificate configuration +NGINX_SSL_PORT=3000 +NGINX_SSL_COUNTRY=US +NGINX_SSL_STATE=State +NGINX_SSL_LOCALITY=City +NGINX_SSL_ORGANIZATION=Organization +NGINX_SSL_UNIT=IT +NGINX_SSL_EMAIL=admin@example.com +NGINX_SSL_DAYS=365 +NGINX_SSL_KEY_SIZE=4096 -# See https://hub.docker.com/r/nanoninja/php-fpm/tags/ -PHP_VERSION=latest +# PHP configuration +PHP_VERSION=8.3 +PHP_TARGET=dev +PHP_INI=php.dev.ini -# MySQL -MYSQL_VERSION=8.0.21 +# MySQL configuration +MYSQL_VERSION=9.2 MYSQL_HOST=mysql +MYSQL_PORT=8989 MYSQL_DATABASE=test -MYSQL_ROOT_USER=root MYSQL_ROOT_PASSWORD=root MYSQL_USER=dev MYSQL_PASSWORD=dev + +# PHPMyAdmin configuration +PHPMYADMIN_PROFILE=dev +PHPMYADMIN_PORT=8080 +PHPMYADMIN_USER=root +PHPMYADMIN_PASSWORD=root +PHPMYADMIN_UPLOAD_LIMIT=100M + +# MailHog configuration +MAILHOG_PROFILE=dev +MAILHOG_SMTP_PORT=1025 +MAILHOG_UI_PORT=8025 +MAILHOG_STORAGE=memory +MAILHOG_HOSTNAME=mailhog +MAILHOG_CORS_ORIGIN=* + +# API documentation configuration +APIDOCS_PROFILE=dev +APIDOCS_PORT=8081 \ No newline at end of file diff --git a/.env.dev b/.env.dev new file mode 100644 index 000000000..f974f425f --- /dev/null +++ b/.env.dev @@ -0,0 +1,55 @@ +# Development environment configuration + +# Application configuration +APP_NAME=docker_nginx_php_mysql +APP_WORKSPACE=default +APP_DIR=app +APP_PUBLIC_DIR=app/public + +# Common settings +NGINX_HOST=localhost +NGINX_PORT=8000 + +# Nginx SSL Certificate configuration +NGINX_SSL_PORT=3000 +NGINX_SSL_COUNTRY=US +NGINX_SSL_STATE=State +NGINX_SSL_LOCALITY=City +NGINX_SSL_ORGANIZATION=Organization +NGINX_SSL_UNIT=IT +NGINX_SSL_EMAIL=admin@example.com +NGINX_SSL_DAYS=365 +NGINX_SSL_KEY_SIZE=4096 + +# PHP configuration +PHP_VERSION=8.3 +PHP_TARGET=dev +PHP_INI=php.dev.ini + +# MySQL configuration +MYSQL_VERSION=9.2 +MYSQL_HOST=mysql +MYSQL_PORT=8989 +MYSQL_DATABASE=test +MYSQL_ROOT_PASSWORD=root +MYSQL_USER=dev +MYSQL_PASSWORD=dev + +# PHPMyAdmin configuration +PHPMYADMIN_PROFILE=dev +PHPMYADMIN_PORT=8080 +PHPMYADMIN_USER=root +PHPMYADMIN_PASSWORD=root +PHPMYADMIN_UPLOAD_LIMIT=100M + +# MailHog configuration +MAILHOG_PROFILE=dev +MAILHOG_SMTP_PORT=1025 +MAILHOG_UI_PORT=8025 +MAILHOG_STORAGE=memory +MAILHOG_HOSTNAME=mailhog +MAILHOG_CORS_ORIGIN=* + +# API documentation configuration +APIDOCS_PROFILE=dev +APIDOCS_PORT=8081 \ No newline at end of file diff --git a/.env.prod b/.env.prod new file mode 100644 index 000000000..cd921e1bf --- /dev/null +++ b/.env.prod @@ -0,0 +1,49 @@ +# Development environment configuration + +# Application configuration +APP_NAME=docker_nginx_php_mysql +APP_WORKSPACE=default +APP_DIR=app +APP_PUBLIC_DIR=app/public + +# Common settings +NGINX_HOST=localhost +NGINX_PORT=8000 + +# Nginx SSL Certificate configuration +NGINX_SSL_PORT=3000 +NGINX_SSL_COUNTRY=US +NGINX_SSL_STATE=State +NGINX_SSL_LOCALITY=City +NGINX_SSL_ORGANIZATION=Organization +NGINX_SSL_UNIT=IT +NGINX_SSL_EMAIL=admin@example.com +NGINX_SSL_DAYS=365 +NGINX_SSL_KEY_SIZE=4096 + +# PHP configuration +PHP_VERSION=8.3 +PHP_TARGET=base +PHP_INI=php.prod.ini + +# MySQL configuration +MYSQL_VERSION=9.2 +MYSQL_HOST=mysql +MYSQL_PORT=8989 +MYSQL_DATABASE=production_db +MYSQL_ROOT_PASSWORD=strong-password +MYSQL_USER=app_user +MYSQL_PASSWORD=strong-password + +# PHPMyAdmin configuration +PHPMYADMIN_PROFILE=none +PHPMYADMIN_PORT=none + +# MailHog configuration +MAILHOG_PROFILE=none +MAILHOG_SMTP_PORT=none +MAILHOG_UI_PORT=none + +# API documentation configuration +APIDOCS_PROFILE=none +APIDOCS_PORT=none \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..f9daf3c18 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,89 @@ +# Contributing to Docker Nginx PHP MySQL + +First of all, thank you for considering contributing to this project! It started as a personal tool, and I've been pleasantly surprised by its popularity and adoption in the community. This makes your interest in contributing all the more appreciated. + +## Important Note + +This project was initially created for personal use, and while I'm delighted that many developers find it useful, I may not always be able to respond quickly to issues or pull requests due to other commitments. I apologize in advance for any delays in my responses. + +## How to Contribute + +Despite the above caveat, contributions are very welcome! Here are some ways you can help improve this project: + +### Reporting Bugs + +If you find a bug, please create an issue on GitHub with: + +- A clear, descriptive title +- A detailed description of the problem +- Steps to reproduce the issue +- Expected and actual behavior +- Screenshots if applicable +- Your environment details (OS, Docker version, etc.) + +### Suggesting Enhancements + +Ideas to improve the project are always welcome. When suggesting an enhancement: + +- Provide a clear description of what you're suggesting +- Explain why this would be valuable to users +- If possible, outline how it could be implemented + +### Pull Requests + +Pull requests are the best way to propose changes: + +1. Fork the repository +2. Create your feature branch: `git checkout -b feature/amazing-feature` +3. Make your changes +4. Update the documentation to reflect your changes +5. Commit your changes: `git commit -m 'Add some amazing feature'` +6. Push to the branch: `git push origin feature/amazing-feature` +7. Open a pull request + +#### Guidelines for Pull Requests + +- Keep changes focused on a single issue +- Follow the existing code style +- Include tests if applicable +- Update documentation as needed +- Ensure all tests pass +- Reference any relevant issues + +## Development Setup + +Please refer to the README.md for instructions on setting up the development environment. + +## Code of Conduct + +### Our Pledge + +In the interest of fostering an open and welcoming environment, we pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +### Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +### Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +## License + +By contributing to this project, you agree that your contributions will be licensed under the same license as the original project. + +Thank you for contributing! diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..7b830a241 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: CI + +on: + push: + branches: [ master, v2-dev ] + pull_request: + branches: [ master, v2-dev ] + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up environment + run: | + cp .env.dev .env + + - name: Start Docker environment + run: make start + + - name: Wait for services to be ready + run: | + echo "Waiting for services to be ready..." + sleep 45 + + - name: Check environment status + run: make status + + - name: Initialize project + run: make init + + - name: Generate API documentation + run: make apidoc + continue-on-error: true + + - name: Generate SSL certificates + run: make gen-certs + + - name: Test database operations + run: | + make db-dump + make db-restore + continue-on-error: true + + - name: Run code quality checks + run: make phpmd + continue-on-error: true + + - name: Run tests + run: make test + continue-on-error: true + + - name: Stop Docker environment + if: always() + run: make stop diff --git a/.gitignore b/.gitignore index 9a4aa7a18..a8879891a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,34 @@ -# Global +# Global system files .*.swp .DS_Store +Thumbs.db -# Application -web/app/composer.json -web/app/composer.lock -web/app/vendor/ -web/app/doc/ -web/app/report/ -data/ - +# IDE specific # PHPStorm .idea/**/workspace.xml .idea/**/tasks.xml .idea/dictionaries -# Netbeans -nbproject/ -/nbproject/ -/nbproject/private/ -/nbproject/private/private.properties - # VSCode .vscode/ -# SSL Certs +# Application +web/app/composer.json +web/app/composer.lock +web/app/vendor/ +web/app/doc/ +web/app/report/ +.phpdoc/ +/docs/api + +# Workspace directories +/web/symfony-app/ +/web/laravel-app/ + +# SSL Certificates etc/ssl/ + +# Temporary files +*.log +*.cache +*.tmp diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8ec197855..000000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -sudo: required - -env: - DOCKER_COMPOSE_VERSION: 1.18.0 - -services: - - docker - -before_install: - - sudo apt update - - sudo rm /usr/local/bin/docker-compose - - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose - - chmod +x docker-compose - - sudo mv docker-compose /usr/local/bin - - docker-compose --version - -before_script: - - sudo make docker-start - - sleep 2m - -script: - - sudo make apidoc - - sudo make gen-certs - - sudo make mysql-dump - - sudo make mysql-restore - - sudo make phpmd - - sudo make test - -after_script: - - sudo make docker-stop \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..ac1399b83 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2025, Nanoninja +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Makefile b/Makefile index b396bfdf2..d7655cfdd 100644 --- a/Makefile +++ b/Makefile @@ -1,82 +1,373 @@ -# Makefile for Docker Nginx PHP Composer MySQL - +# Include environment variables include .env -# MySQL -MYSQL_DUMPS_DIR=data/db/dumps +# Variables for color management +ifndef NOCOLOR + GREEN = \033[0;32m + YELLOW = \033[0;33m + BLUE = \033[0;34m + NC = \033[0m # No Color +else + GREEN = + YELLOW = + BLUE = + NC = +endif + +# Variable definitions +DOCKER_COMPOSE = docker compose +DOCKER_EXEC = docker compose exec -T +PHP_CONTAINER = php +MYSQL_CONTAINER = $(shell docker compose ps -q mysqldb 2>/dev/null) +WEB_ROOT = $(shell pwd)/web +APP_DIR ?= app +APP_ROOT = $(WEB_ROOT)/$(APP_DIR) +MYSQL_DUMPS_DIR = data/db/dumps +CURRENT_USER = $(shell whoami) +CURRENT_UID = $(shell id -u) +CURRENT_GID = $(shell id -g) + +# Main commands +.PHONY: help init dev prod start stop restart status logs + +# Internal target to check if the application directory exists +check-app-dir: + @if [ ! -d "$(APP_ROOT)" ]; then \ + echo "${YELLOW}Directory '$(APP_DIR)' does not exist. Please update APP_DIR in .env or create the directory.${NC}"; \ + exit 1; \ + fi help: @echo "" - @echo "usage: make COMMAND" + @echo "${BLUE}Docker Nginx PHP MySQL - Version 2.0${NC}" + @echo "" + @echo "${GREEN}Usage:${NC} make ${YELLOW}${NC}" + @echo "" + @echo "${GREEN}Environment commands:${NC}" + @echo " ${YELLOW}init${NC} Initialize the project" + @echo " ${YELLOW}dev${NC} Set up development environment" + @echo " ${YELLOW}prod${NC} Set up production environment" + @echo " ${YELLOW}start${NC} Start all containers" + @echo " ${YELLOW}stop${NC} Stop all containers" + @echo " ${YELLOW}restart${NC} Restart all containers" + @echo " ${YELLOW}status${NC} Display containers status" + @echo " ${YELLOW}logs${NC} Follow log output" + @echo "" + @echo "${GREEN}Development commands:${NC}" + @echo " ${YELLOW}composer-install${NC} Install PHP dependencies with Composer" + @echo " ${YELLOW}composer-update${NC} Update PHP dependencies with Composer" + @echo " ${YELLOW}composer-autoload${NC} Update autoloader" + @echo " ${YELLOW}composer-script${NC} Run Composer scripts (e.g., make composer-script SCRIPT=test ARGS=\"--verbose --filter=Class\")" + @echo " ${YELLOW}test${NC} Run tests" + @echo " ${YELLOW}code-sniff${NC} Check code with PHP Code Sniffer (PSR2)" + @echo " ${YELLOW}phpmd${NC} Analyze code with PHP Mess Detector" + @echo "" + @echo "${GREEN}Database commands:${NC}" + @echo " ${YELLOW}db-dump${NC} Create backup of all databases" + @echo " ${YELLOW}db-restore${NC} Restore backup of all databases" + @echo "" + @echo "${GREEN}Utility commands:${NC}" + @echo " ${YELLOW}gen-certs${NC} Generate SSL certificates" + @echo " ${YELLOW}enable-ssl${NC} Enable SSL in Nginx configuration" + @echo "" + @echo "${GREEN}Framework commands:${NC}" + @echo " ${YELLOW}install-symfony${NC} Install Symfony framework" + @echo " ${YELLOW}install-laravel${NC} Install Laravel framework" + @echo "" + @echo "${GREEN}Debugging commands:${NC}" + @echo " ${YELLOW}xdebug-check${NC} Check Xdebug configuration" + @echo " ${YELLOW}xdebug-restart${NC} Restart PHP container with Xdebug" + @echo "" + @echo "${GREEN}Documentation commands:${NC}" + @echo " ${YELLOW}apidocs-generate${NC} Generate API documentation" + @echo " ${YELLOW}apidocs-serve${NC} Serve the API documentation via web server" + @echo " ${YELLOW}apidocs${NC} Generate and serve API documentation" + @echo "" + @echo "${GREEN}Container access commands:${NC}" + @echo " ${YELLOW}php-connect${NC} Connect to PHP container shell" + @echo " ${YELLOW}db-connect${NC} Connect to MySQL shell" + @echo "" + @echo "${GREEN}Application directory:${NC}" + @echo " Current application directory: ${YELLOW}$(APP_DIR)${NC}" + @echo " To change, update APP_DIR in .env file or use APP_DIR= make " @echo "" - @echo "Commands:" - @echo " apidoc Generate documentation of API" - @echo " code-sniff Check the API with PHP Code Sniffer (PSR2)" - @echo " clean Clean directories for reset" - @echo " composer-up Update PHP dependencies with composer" - @echo " docker-start Create and start containers" - @echo " docker-stop Stop and clear all services" - @echo " gen-certs Generate SSL certificates" - @echo " logs Follow log output" - @echo " mysql-dump Create backup of all databases" - @echo " mysql-restore Restore backup of all databases" - @echo " phpmd Analyse the API with PHP Mess Detector" - @echo " test Test application" - -init: - @$(shell cp -n $(shell pwd)/web/app/composer.json.dist $(shell pwd)/web/app/composer.json 2> /dev/null) - -apidoc: - @docker run --rm -v $(shell pwd):/data phpdoc/phpdoc -i=vendor/ -d /data/web/app/src -t /data/web/app/doc - @make resetOwner - -clean: - @rm -Rf data/db/mysql/* - @rm -Rf $(MYSQL_DUMPS_DIR)/* - @rm -Rf web/app/vendor - @rm -Rf web/app/composer.lock - @rm -Rf web/app/doc - @rm -Rf web/app/report - @rm -Rf etc/ssl/* - -code-sniff: - @echo "Checking the standard code..." - @docker-compose exec -T php ./app/vendor/bin/phpcs -v --standard=PSR2 app/src - -composer-up: - @docker run --rm -v $(shell pwd)/web/app:/app composer update - -docker-start: init - docker-compose up -d - -docker-stop: - @docker-compose down -v - @make clean -gen-certs: - @docker run --rm -v $(shell pwd)/etc/ssl:/certificates -e "SERVER=$(NGINX_HOST)" jacoelho/generate-certificate +init: check-env composer-dist composer-install + @echo "${GREEN}Project initialized successfully!${NC}" + +check-env: + @if [ ! -f .env ]; then \ + echo "${BLUE}Creating default .env file...${NC}"; \ + cp .env.dev .env; \ + echo "${GREEN}.env file created!${NC}"; \ + fi + +dev: + @echo "${BLUE}Setting up development environment...${NC}" + @cp -f .env.dev .env + @$(MAKE) restart + @echo "${GREEN}Development environment is ready!${NC}" + +prod: + @echo "${BLUE}Setting up production environment...${NC}" + @cp -f .env.prod .env + @$(MAKE) restart + @echo "${GREEN}Production environment is ready!${NC}" + @echo "${YELLOW}Note: This is a simulated production environment. For real production, additional configurations may be needed.${NC}" + +start: + @echo "${BLUE}Starting containers...${NC}" + @if grep -q "PHP_TARGET=dev" .env; then \ + echo "${BLUE}Development environment detected, enabling PHPMyAdmin...${NC}"; \ + $(DOCKER_COMPOSE) --profile dev up -d; \ + else \ + $(DOCKER_COMPOSE) up -d; \ + fi + @echo "${GREEN}Containers started!${NC}" + @echo "${GREEN}Using application directory: $(APP_DIR)${NC}" + +stop: + @echo "${BLUE}Stopping containers...${NC}" + @$(DOCKER_COMPOSE) down + @echo "${GREEN}Containers stopped!${NC}" + +restart: stop start + +status: + @$(DOCKER_COMPOSE) ps logs: - @docker-compose logs -f + @$(DOCKER_COMPOSE) logs -f -mysql-dump: +# Development commands +.PHONY: composer-dist composer-install composer-update composer-autoload composer-script test code-sniff phpmd + +composer-dist: check-app-dir + @if [ ! -f $(APP_ROOT)/composer.json ]; then \ + echo "${BLUE}Creating composer.json file in $(APP_DIR)...${NC}"; \ + mkdir -p $(APP_ROOT); \ + if [ -f "composer.json.dist" ]; then \ + cp composer.json.dist $(APP_ROOT)/composer.json; \ + elif [ -f "$(WEB_ROOT)/composer.json.dist" ]; then \ + cp $(WEB_ROOT)/composer.json.dist $(APP_ROOT)/composer.json; \ + else \ + echo "{}" > $(APP_ROOT)/composer.json; \ + fi; \ + echo "${GREEN}composer.json created!${NC}"; \ + else \ + echo "${YELLOW}composer.json already exists in $(APP_DIR).${NC}"; \ + echo "${YELLOW}If you want to reset it, please remove the file first.${NC}"; \ + fi + +composer-install: check-app-dir + @echo "${BLUE}Installing PHP dependencies in $(APP_DIR)...${NC}" + @$(DOCKER_EXEC) $(PHP_CONTAINER) composer install -d /var/www/html/$(APP_DIR) + @$(MAKE) reset-owner dir=$(APP_ROOT) + @echo "${GREEN}Dependencies installed!${NC}" + +composer-update: check-app-dir + @echo "${BLUE}Updating PHP dependencies in $(APP_DIR)...${NC}" + @$(DOCKER_EXEC) $(PHP_CONTAINER) composer update -d /var/www/html/$(APP_DIR) + @$(MAKE) reset-owner dir=$(APP_ROOT) + @echo "${GREEN}Dependencies updated!${NC}" + +composer-autoload: check-app-dir + @echo "${BLUE}Updating autoloader in $(APP_DIR)...${NC}" + @$(DOCKER_EXEC) $(PHP_CONTAINER) composer dump-autoload -d /var/www/html/$(APP_DIR) + @$(MAKE) reset-owner dir=$(APP_ROOT) + @echo "${GREEN}Autoloader updated!${NC}" + +# Composer script command with dynamic arguments +composer-script: check-app-dir + @echo "${BLUE}Running Composer script in $(APP_DIR)...${NC}" + @if [ -z "$(SCRIPT)" ]; then \ + echo "${YELLOW}Please specify a script name: make composer-script SCRIPT=your-script-name${NC}"; \ + echo "${YELLOW}Available scripts:${NC}"; \ + $(DOCKER_EXEC) $(PHP_CONTAINER) composer run-script --list -d /var/www/html/$(APP_DIR) 2>/dev/null || echo "${YELLOW}No scripts defined in composer.json${NC}"; \ + exit 1; \ + fi + @echo "${BLUE}Executing: composer run-script $(SCRIPT) $(ARGS)${NC}" + @$(DOCKER_EXEC) $(PHP_CONTAINER) composer run-script $(SCRIPT) $(ARGS) -d /var/www/html/$(APP_DIR) + @$(MAKE) reset-owner dir=$(APP_ROOT) + @echo "${GREEN}Script execution completed!${NC}" + +test: check-app-dir + @echo "${BLUE}Running tests in $(APP_DIR)...${NC}" + @if [ -f "$(APP_ROOT)/vendor/bin/phpunit" ]; then \ + $(DOCKER_EXEC) $(PHP_CONTAINER) ./$(APP_DIR)/vendor/bin/phpunit --colors=always --configuration ./$(APP_DIR)/; \ + else \ + echo "${YELLOW}PHPUnit not found in $(APP_DIR). Please run composer-install first.${NC}"; \ + exit 1; \ + fi + @$(MAKE) reset-owner dir=$(APP_ROOT) + @echo "${GREEN}Tests completed!${NC}" + +code-sniff: check-app-dir + @echo "${BLUE}Checking code according to PSR2 in $(APP_DIR)...${NC}" + @if [ -f "$(APP_ROOT)/vendor/bin/phpcs" ]; then \ + $(DOCKER_EXEC) $(PHP_CONTAINER) ./$(APP_DIR)/vendor/bin/phpcs -v --standard=PSR2 $(APP_DIR)/src; \ + else \ + echo "${YELLOW}PHP_CodeSniffer not found in $(APP_DIR). Please run composer-install first.${NC}"; \ + exit 1; \ + fi + @echo "${GREEN}Check completed!${NC}" + +phpmd: check-app-dir + @echo "${BLUE}Analyzing code with PHP Mess Detector in $(APP_DIR)...${NC}" + @if [ -f "$(APP_ROOT)/vendor/bin/phpmd" ]; then \ + $(DOCKER_EXEC) $(PHP_CONTAINER) \ + ./$(APP_DIR)/vendor/bin/phpmd \ + ./$(APP_DIR)/src text cleancode,codesize,controversial,design,naming,unusedcode; \ + else \ + echo "${YELLOW}PHP Mess Detector not found in $(APP_DIR). Please run composer-install first.${NC}"; \ + exit 1; \ + fi + @echo "${GREEN}Analysis completed!${NC}" + +# Database commands +.PHONY: db-dump db-restore db-connect + +db-dump: + @echo "${BLUE}Creating database backup...${NC}" @mkdir -p $(MYSQL_DUMPS_DIR) - @docker exec $(shell docker-compose ps -q mysqldb) mysqldump --all-databases -u"$(MYSQL_ROOT_USER)" -p"$(MYSQL_ROOT_PASSWORD)" > $(MYSQL_DUMPS_DIR)/db.sql 2>/dev/null - @make resetOwner + @if [ -z "$(MYSQL_CONTAINER)" ]; then \ + echo "${YELLOW}MySQL container is not running!${NC}"; \ + else \ + docker exec $(MYSQL_CONTAINER) mysqldump --all-databases -u"$${MYSQL_ROOT_USER}" -p"$${MYSQL_ROOT_PASSWORD}" > $(MYSQL_DUMPS_DIR)/db.sql 2>/dev/null; \ + $(MAKE) reset-owner dir=$(MYSQL_DUMPS_DIR); \ + echo "${GREEN}Backup created in $(MYSQL_DUMPS_DIR)/db.sql!${NC}"; \ + fi + +db-restore: + @echo "${BLUE}Restoring database...${NC}" + @if [ -z "$(MYSQL_CONTAINER)" ]; then \ + echo "${YELLOW}MySQL container is not running!${NC}"; \ + elif [ ! -f "$(MYSQL_DUMPS_DIR)/db.sql" ]; then \ + echo "${YELLOW}Backup file not found at $(MYSQL_DUMPS_DIR)/db.sql!${NC}"; \ + else \ + echo "${YELLOW}WARNING: This will overwrite existing database data!${NC}"; \ + echo "${YELLOW}Are you sure you want to continue? [y/N] ${NC}"; \ + read -r confirmation; \ + if [ "$$confirmation" = "y" ] || [ "$$confirmation" = "Y" ]; then \ + docker exec -i $(MYSQL_CONTAINER) mysql -u"$${MYSQL_ROOT_USER}" -p"$${MYSQL_ROOT_PASSWORD}" < $(MYSQL_DUMPS_DIR)/db.sql 2>/dev/null; \ + echo "${GREEN}Database restored!${NC}"; \ + else \ + echo "${BLUE}Operation canceled.${NC}"; \ + fi \ + fi + +db-connect: + @echo "${BLUE}Connecting to MySQL shell...${NC}" + @if [ -z "$(MYSQL_CONTAINER)" ]; then \ + echo "${YELLOW}MySQL container is not running!${NC}"; \ + else \ + docker exec -it $(MYSQL_CONTAINER) mysql -uroot -p${MYSQL_ROOT_PASSWORD}; \ + fi + +# Utility commands +.PHONY: php-connect gen-certs enable-ssl apidocs-generate apidocs-serve apidocs reset-owner + +php-connect: + @echo "${BLUE}Connecting to PHP container shell...${NC}" + @if ! $(DOCKER_COMPOSE) ps --services --filter "status=running" | grep -q $(PHP_CONTAINER); then \ + echo "${YELLOW}PHP container is not running!${NC}"; \ + exit 1; \ + fi + @$(DOCKER_COMPOSE) exec -it $(PHP_CONTAINER) bash + @echo "${GREEN}PHP container shell session ended.${NC}" + +gen-certs: + @echo "${BLUE}Generating SSL certificates...${NC}" + @docker build -t ssl-generator docker/ssl + @docker run --rm -v $(shell pwd)/etc/ssl:/certificates \ + -e SERVER=${NGINX_HOST} \ + -e COUNTRY=${NGINX_SSL_COUNTRY} \ + -e STATE=${NGINX_SSL_STATE} \ + -e LOCALITY=${NGINX_SSL_LOCALITY} \ + -e ORGANIZATION=${NGINX_SSL_ORGANIZATION} \ + -e ORGANIZATIONAL_UNIT=${NGINX_SSL_UNIT} \ + -e EMAIL=${NGINX_SSL_EMAIL} \ + -e CERT_EXPIRY=${NGINX_SSL_DAYS} \ + -e KEY_SIZE=${NGINX_SSL_KEY_SIZE} \ + ssl-generator + @$(MAKE) reset-owner dir=$(shell pwd)/etc/ssl + @echo "${GREEN}Certificates generated!${NC}" + +enable-ssl: + @echo "${BLUE}Enabling SSL in Nginx configuration...${NC}" + @docker run --rm \ + -v $(PWD)/etc/nginx:/etc/nginx \ + alpine:latest \ + sh -c 'apk add --no-cache sed && sed -i "/^# server {/,/^# }/ s/^# //" /etc/nginx/default.template.conf && sed -i "/^#[[:space:]]*$$/s/^#//" /etc/nginx/default.template.conf' + @$(MAKE) restart + @echo "${GREEN}SSL has been enabled. Access your site at https://${NGINX_HOST}:3000${NC}" + +apidocs-generate: + @echo "${BLUE}Generating API documentation for $(APP_DIR)...${NC}" + @if [ ! -d "$(APP_ROOT)/src" ]; then \ + echo "${YELLOW}Source directory $(APP_DIR)/src not found!${NC}"; \ + exit 1; \ + fi + @mkdir -p ./docs/api/html + @docker run --rm -v $(shell pwd):/data phpdoc/phpdoc -i=vendor/ -d /data/web/$(APP_DIR)/src -t /data/docs/api/html + @$(MAKE) reset-owner dir=./docs/api + @echo "${GREEN}Documentation generated in ./docs/api/html!${NC}" + +apidocs-serve: + @echo "${BLUE}Starting API documentation server...${NC}" + @$(DOCKER_COMPOSE) --profile dev up -d apidocs + @echo "${GREEN}API documentation available at http://localhost:8081${NC}" + +apidocs: apidocs-generate apidocs-serve + @echo "${BLUE}API documentation is now ready and being served.${NC}" + +reset-owner: + @chown -R $(CURRENT_USER):$(CURRENT_GID) $(dir) 2>/dev/null || true + +# Framework commands +.PHONY: install-symfony install-laravel -mysql-restore: - @docker exec -i $(shell docker-compose ps -q mysqldb) mysql -u"$(MYSQL_ROOT_USER)" -p"$(MYSQL_ROOT_PASSWORD)" < $(MYSQL_DUMPS_DIR)/db.sql 2>/dev/null +install-symfony: + @echo "${BLUE}Installing Symfony framework...${NC}" + @if [ -d "$(WEB_ROOT)/symfony-app" ]; then \ + echo "${YELLOW}WARNING: Directory 'symfony-app' already exists!${NC}"; \ + echo "${YELLOW}Please remove or rename the existing directory before installing Symfony.${NC}"; \ + exit 1; \ + fi + @$(DOCKER_EXEC) $(PHP_CONTAINER) bash -c "cd /var/www/html && composer create-project symfony/skeleton symfony-app" + @$(MAKE) reset-owner dir=$(WEB_ROOT)/symfony-app + @echo "${GREEN}Symfony installed in ./web/symfony-app!${NC}" + @echo "${YELLOW}To configure your environment for Symfony, update these variables in .env:${NC}" + @echo "${YELLOW}APP_WORKSPACE=symfony${NC}" + @echo "${YELLOW}APP_DIR=symfony-app${NC}" + @echo "${YELLOW}Then restart the containers with: make restart${NC}" -phpmd: - @docker-compose exec -T php \ - ./app/vendor/bin/phpmd \ - ./app/src text cleancode,codesize,controversial,design,naming,unusedcode +install-laravel: + @echo "${BLUE}Installing Laravel framework...${NC}" + @if [ -d "$(WEB_ROOT)/laravel-app" ]; then \ + echo "${YELLOW}WARNING: Directory 'laravel-app' already exists!${NC}"; \ + echo "${YELLOW}Please remove or rename the existing directory before installing Laravel.${NC}"; \ + exit 1; \ + fi + @$(DOCKER_EXEC) $(PHP_CONTAINER) bash -c "cd /var/www/html && composer create-project laravel/laravel laravel-app" + @$(MAKE) reset-owner dir=$(WEB_ROOT)/laravel-app + @echo "${GREEN}Laravel installed in ./web/laravel-app!${NC}" + @echo "${YELLOW}To configure your environment for Laravel, update these variables in .env:${NC}" + @echo "${YELLOW}APP_WORKSPACE=laravel${NC}" + @echo "${YELLOW}APP_DIR=laravel-app${NC}" + @echo "${YELLOW}Then restart the containers with: make restart${NC}" -test: code-sniff - @docker-compose exec -T php ./app/vendor/bin/phpunit --colors=always --configuration ./app/ - @make resetOwner +# Debugging commands +.PHONY: xdebug-check xdebug-restart -resetOwner: - @$(shell chown -Rf $(SUDO_USER):$(shell id -g -n $(SUDO_USER)) $(MYSQL_DUMPS_DIR) "$(shell pwd)/etc/ssl" "$(shell pwd)/web/app" 2> /dev/null) +xdebug-check: + @echo "${BLUE}Checking Xdebug configuration...${NC}" + @$(DOCKER_EXEC) $(PHP_CONTAINER) php -v + @$(DOCKER_EXEC) $(PHP_CONTAINER) php -i | grep -i xdebug + @echo "${GREEN}Xdebug check completed!${NC}" -.PHONY: clean test code-sniff init \ No newline at end of file +xdebug-restart: + @echo "${BLUE}Restarting PHP container with Xdebug...${NC}" + @$(DOCKER_COMPOSE) restart php + @echo "${GREEN}PHP container restarted!${NC}" + @$(MAKE) xdebug-check \ No newline at end of file diff --git a/README.md b/README.md index faae0b8b9..501ae8591 100644 --- a/README.md +++ b/README.md @@ -1,377 +1,597 @@ -# Nginx PHP MySQL [![Build Status](https://travis-ci.org/nanoninja/docker-nginx-php-mysql.svg?branch=master)](https://travis-ci.org/nanoninja/docker-nginx-php-mysql) [![GitHub version](https://badge.fury.io/gh/nanoninja%2Fdocker-nginx-php-mysql.svg)](https://badge.fury.io/gh/nanoninja%2Fdocker-nginx-php-mysql) +# Docker Nginx PHP MySQL -Docker running Nginx, PHP-FPM, Composer, MySQL and PHPMyAdmin. +[![GitHub version](https://badge.fury.io/gh/nanoninja%2Fdocker-nginx-php-mysql.svg)](https://badge.fury.io/gh/nanoninja%2Fdocker-nginx-php-mysql) +[![GitHub Actions](https://github.com/nanoninja/docker-nginx-php-mysql/workflows/CI/badge.svg)](https://github.com/nanoninja/docker-nginx-php-mysql/actions) -## Overview +A complete and modern Docker development environment for PHP applications with Nginx, PHP-FPM, Composer, MySQL and PHPMyAdmin. -1. [Install prerequisites](#install-prerequisites) +## 🚀 Features - Before installing project make sure the following prerequisites have been met. +- Easy switch between PHP versions (8.2, 8.3, etc.) +- Environment configurations for development and production +- Support for multiple PHP frameworks (Symfony, Laravel, etc.) +- Two network layers (frontend and backend) for better security +- Integrated Composer for dependency management +- Xdebug for debugging (in development environment) +- Health checks for all services +- Comprehensive Makefile with helpful commands +- PHPMyAdmin for database management (in development environment) -2. [Clone the project](#clone-the-project) +## 📋 Requirements - We’ll download the code from its repository on GitHub. +- Docker Engine (20.10+) +- Docker Compose (2.0+) +- Make (optional, but recommended) -3. [Configure Nginx With SSL Certificates](#configure-nginx-with-ssl-certificates) [`Optional`] +### Command Line Reference - We'll generate and configure SSL certificate for nginx before running server. +For users who don't have access to the `make` utility, a complete reference of all available commands with their manual alternatives is provided in the [Command Line Reference](docs/commands.md) document. -4. [Configure Xdebug](#configure-xdebug) [`Optional`] +## 🛠️ Installation - We'll configure Xdebug for IDE (PHPStorm or Netbeans). +### Clone the repository -5. [Run the application](#run-the-application) - - By this point we’ll have all the project pieces in place. - -6. [Use Makefile](#use-makefile) [`Optional`] - - When developing, you can use `Makefile` for doing recurrent operations. +```bash +git clone https://github.com/nanoninja/docker-nginx-php-mysql.git +cd docker-nginx-php-mysql +``` -7. [Use Docker Commands](#use-docker-commands) +## 🏁 Getting Started - When running, you can use docker commands for doing recurrent operations. +Setting up your development environment involves just a few simple steps: -___ +### 1. Start the Docker environment -## Install prerequisites +First, start all the Docker containers required for the environment: -To run the docker commands without using **sudo** you must add the **docker** group to **your-user**: +```bash +# Start with default environment (development) +make start +# Or explicitly select an environment before starting +make dev # For development mode +make prod # For production mode ``` -sudo usermod -aG docker your-user -``` - -For now, this project has been mainly created for Unix `(Linux/MacOS)`. Perhaps it could work on Windows. -All requisites should be available for your distribution. The most important are : +### 2. Initialize the project -* [Git](https://git-scm.com/downloads) -* [Docker](https://docs.docker.com/engine/installation/) -* [Docker Compose](https://docs.docker.com/compose/install/) +After the containers are running, initialize the project to install dependencies and set up the environment: -Check if `docker-compose` is already installed by entering the following command : - -```sh -which docker-compose +```bash +make init ``` -Check Docker Compose compatibility : - -* [Compose file version 3 reference](https://docs.docker.com/compose/compose-file/) +This command will: -The following is optional but makes life more enjoyable : +- Copy the composer configuration template +- Install PHP dependencies via Composer +- Set up the appropriate file permissions +- Prepare the environment for development -```sh -which make -``` +### 3. Access your application -On Ubuntu and Debian these are available in the meta-package build-essential. On other distributions, you may need to install the GNU C++ compiler separately. +Once the environment is running and initialized, you can access: -```sh -sudo apt install build-essential -``` +- Web: [http://localhost:8000](http://localhost:8000) +- Secure Web: [https://localhost:3000](https://localhost:3000) (SSL certificates must be configured) +- PHPMyAdmin: [http://localhost:8080](http://localhost:8080) (username: dev, password: dev) -### Images to use +### 4. Stop the environment when finished -* [Nginx](https://hub.docker.com/_/nginx/) -* [MySQL](https://hub.docker.com/_/mysql/) -* [PHP-FPM](https://hub.docker.com/r/nanoninja/php-fpm/) -* [Composer](https://hub.docker.com/_/composer/) -* [PHPMyAdmin](https://hub.docker.com/r/phpmyadmin/phpmyadmin/) -* [Generate Certificate](https://hub.docker.com/r/jacoelho/generate-certificate/) - -You should be careful when installing third party web servers such as MySQL or Nginx. +```bash +make stop +``` -This project use the following ports : +## 🔄 Environment Management -| Server | Port | -|------------|------| -| MySQL | 8989 | -| PHPMyAdmin | 8080 | -| Nginx | 8000 | -| Nginx SSL | 3000 | +This project supports both development and production environments. Each environment has its own configuration optimized for its specific use case. -___ +### Development Environment -## Clone the project +The development environment includes: +- Xdebug for debugging +- PHPMyAdmin for database management +- Development-oriented PHP settings +- Detailed error reporting -To install [Git](http://git-scm.com/book/en/v2/Getting-Started-Installing-Git), download it and install following the instructions : +To activate: -```sh -git clone https://github.com/nanoninja/docker-nginx-php-mysql.git +```bash +make dev ``` -Go to the project directory : +### Production Environment -```sh -cd docker-nginx-php-mysql -``` +The production environment is optimized for performance and security: +- Disabled development tools +- Optimized PHP settings +- Minimized error reporting +- Enhanced security configurations -### Project tree +To activate: -```sh -. -├── Makefile -├── README.md -├── data -│ └── db -│ ├── dumps -│ └── mysql -├── doc -├── docker-compose.yml -├── etc -│ ├── nginx -│ │ ├── default.conf -│ │ └── default.template.conf -│ ├── php -│ │ └── php.ini -│ └── ssl -└── web - ├── app - │ ├── composer.json.dist - │ ├── phpunit.xml.dist - │ ├── src - │ │ └── Foo.php - │ └── test - │ ├── FooTest.php - │ └── bootstrap.php - └── public - └── index.php +```bash +make prod ``` -___ - -## Configure Nginx With SSL Certificates - -You can change the host name by editing the `.env` file. - -If you modify the host name, do not forget to add it to the `/etc/hosts` file. - -1. Generate SSL certificates - - ```sh - source .env && docker run --rm -v $(pwd)/etc/ssl:/certificates -e "SERVER=$NGINX_HOST" jacoelho/generate-certificate - ``` - -2. Configure Nginx - - Do not modify the `etc/nginx/default.conf` file, it is overwritten by `etc/nginx/default.template.conf` - - Edit nginx file `etc/nginx/default.template.conf` and uncomment the SSL server section : - - ```sh - # server { - # server_name ${NGINX_HOST}; - # - # listen 443 ssl; - # fastcgi_param HTTPS on; - # ... - # } - ``` - -___ +### Customizing Environments + +You can customize the environments by editing: +- `.env.dev` for development settings +- `.env.prod` for production settings + +Common configuration options: + +| Variable | Description | Default (Dev) | Default (Prod) | +|------------------------|---------------------------------------|----------------------|----------------------| +| APP_NAME | Project name for Docker volumes | docker_nginx_php_mysql | docker_nginx_php_mysql | +| APP_WORKSPACE | Workspace type | default | default | +| APP_DIR | Application directory | app | app | +| APP_PUBLIC_DIR | Public directory (auto-generated) | app/public | app/public | +| NGINX_HOST | Nginx server hostname | localhost | your-domain.com | +| NGINX_PORT | Nginx HTTP port | 8000 | 8000 | +| NGINX_SSL_PORT | Nginx HTTPS port | 3000 | 3000 | +| PHP_VERSION | PHP version to use | 8.3 | 8.3 | +| PHP_TARGET | PHP image target | dev | base | +| PHP_INI | PHP configuration file | php.dev.ini | php.prod.ini | +| XDEBUG_ENABLED | Enable Xdebug | 1 | 0 | +| MYSQL_VERSION | MySQL version | 9.2 | 9.2 | +| MYSQL_HOST | MySQL server hostname | mysql | mysql | +| MYSQL_PORT | MySQL server port | 8989 | 8989 | +| MYSQL_DATABASE | MySQL database name | test | production_db | +| MYSQL_ROOT_PASSWORD | MySQL root password | root | [strong-password] | +| MYSQL_USER | MySQL application user | dev | app_user | +| MYSQL_PASSWORD | MySQL application password | dev | [strong-password] | +| PHPMYADMIN_PORT | PHPMyAdmin web interface port | 8080 | none | +| PHPMYADMIN_PROFILE | PHPMyAdmin Docker profile | dev | none | +| MAILHOG_SMTP_PORT | MailHog SMTP port | 1025 | none | +| MAILHOG_UI_PORT | MailHog web interface port | 8025 | none | +| MAILHOG_PROFILE | MailHog Docker profile | dev | none | +| APIDOCS_PORT | API docs web interface port | 8081 | none | +| APIDOCS_PROFILE | API docs Docker profile | dev | none | + +## 🔍 Debugging with Xdebug + +This environment comes with Xdebug pre-configured in the development setup, allowing you to debug your PHP applications effectively. This section provides detailed instructions on how to configure and use Xdebug with popular IDEs. + +### How Xdebug Works in This Environment + +In the development environment (`make dev`), Xdebug is automatically enabled in the PHP container. The configuration includes: + +- Xdebug mode set to `develop,debug` +- Automatic connection to your host machine +- Start with request enabled +- Debug port set to 9003 (Xdebug 3 default) + +### Configuration for Visual Studio Code + +VS Code requires the PHP Debug extension to work with Xdebug. Here's how to set it up: + +1. **Install the PHP Debug extension** + - Open VS Code + - Go to Extensions (Ctrl+Shift+X or Cmd+Shift+X) + - Search for "PHP Debug" by Felix Becker + - Click Install + +2. **Create a launch configuration** + - Create a `.vscode` directory in your project root + - Create a file named `launch.json` inside the `.vscode` directory + - Add the following configuration: + +```json +{ + "configurations": [ + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003, + "pathMappings": { + "/var/www/html": "${workspaceFolder}/web" + }, + "log": true, + "xdebugSettings": { + "max_data": 65535, + "show_hidden": 1, + "max_children": 100, + "max_depth": 5 + } + } + ] +} +``` -## Configure Xdebug +When using Xdebug with Docker and VSCode, it's crucial to correctly configure the path mapping between your local filesystem and the Docker container's filesystem. -If you use another IDE than [PHPStorm](https://www.jetbrains.com/phpstorm/) or [Netbeans](https://netbeans.org/), go to the [remote debugging](https://xdebug.org/docs/remote) section of Xdebug documentation. +In our configuration, the local directory `./web` is mounted to the path `/var/www/html` in the container. This distinction is essential for understanding how to configure VSCode. -For a better integration of Docker to PHPStorm, use the [documentation](https://github.com/nanoninja/docker-nginx-php-mysql/blob/master/doc/phpstorm-macosx.md). +Your `launch.json` file in VSCode should contain the following mapping: -1. Get your own local IP address : +```json +"pathMappings": { + "/var/www/html": "${workspaceFolder}/web" +} +``` - ```sh - sudo ifconfig - ``` +3. **Start debugging** + - Set breakpoints in your code by clicking in the gutter next to line numbers + - Start the debugging session in VS Code (F5 or click the green play button in the Debug panel) + - Access your application in the browser + - VS Code should stop at your breakpoints + +### Configuration for PHPStorm + +PHPStorm has built-in support for Xdebug. Here's how to configure it: + +1. **Configure the PHP interpreter** + - Go to Settings/Preferences → PHP + - Add a new CLI Interpreter → From Docker + - Select the PHP container from your docker-compose configuration + - PHPStorm should detect Xdebug automatically + +2. **Set up the server configuration** + - Go to Settings/Preferences → PHP → Servers + - Add a new server: + - Name: docker + - Host: localhost + - Port: 8000 + - Check "Use path mappings" + - Map your project root to `/var/www/html` + +3. **Configure Xdebug** + - Go to Settings/Preferences → PHP → Debug + - Ensure Xdebug is set to port 9003 + - Enable "Can accept external connections" + +4. **Start debugging** + - Set breakpoints in your code + - Click on the "Start Listening for PHP Debug Connections" button (telephone icon) + - Access your application in the browser + - PHPStorm should stop at your breakpoints + +### Troubleshooting Xdebug + +If you're having issues with Xdebug, try these common solutions: + +1. **Verify Xdebug is enabled** + ```bash + docker-compose exec php php -m | grep xdebug + ``` + This should return "xdebug" if it's enabled. + +2. **Check Xdebug settings** + ```bash + docker-compose exec php php -i | grep xdebug + ``` + Review the settings to ensure they match what you expect. + +3. **Ensure correct network settings** + If your host IP address is different or you're using a VPN, you might need to adjust the Xdebug client host in `etc/php/php.ini`: + ```ini + xdebug.client_host=host.docker.internal + ``` + + On Linux, you might need to use your actual host IP or add `extra_hosts` to your docker-compose.yml: + ```yaml + services: + php: + extra_hosts: + - "host.docker.internal:host-gateway" + ``` + +4. **Browser extensions** + Install browser extensions to easily toggle Xdebug sessions: + - For Chrome: "Xdebug Helper" + - For Firefox: "Xdebug Helper" or "Xdebug Extension" + +### Customizing Xdebug Settings + +You can customize Xdebug by editing the `etc/php/php.ini` file. Here are some useful settings you might want to adjust: + +```ini +; Adjust max nesting level if you have deeply nested function calls +xdebug.max_nesting_level=1000 + +; Increase var display max depth for complex objects +xdebug.var_display_max_depth=10 + +; Increase var display max children +xdebug.var_display_max_children=256 + +; Increase var display max data +xdebug.var_display_max_data=1024 +``` -2. Edit php file `etc/php/php.ini` and comment or uncomment the configuration as needed. +After changing any settings, restart the containers: -3. Set the `remote_host` parameter with your IP : +```bash +make restart +``` - ```sh - xdebug.remote_host=192.168.0.1 # your IP - ``` -___ +With this setup, you'll have a powerful debugging environment that helps you identify and fix issues in your PHP applications efficiently. -## Run the application +## ⚙️ Project Structure -1. Copying the composer configuration file : +``` +. +├── docker/ # Docker configuration +│ ├── php/ # PHP Dockerfile +│ ├── ssl/ # SSL certificate generator +│ └── mysql/ # MySQL initialization scripts +├── etc/ # Configuration files +│ ├── nginx/ # Nginx configuration +│ │ └── workspace/ # Workspace-specific configs +│ ├── php/ # PHP configuration +│ └── ssl/ # SSL certificates +├── web/ # Web root directory +│ └── app/ # Default application code +│ ├── public/ # Public files +│ ├── src/ # Source files +│ └── tests/ # Test code +├── docs/ # Documentation +│ ├── api/ # API documentation (generated) +│ └── *.md # Markdown documentation files +├── data/ # Persistent data +│ └── db/ # Database files +│ └── dumps/ # Database dumps +├── .env.dev # Development environment variables +├── .env.prod # Production environment variables +├── docker-compose.yml # Docker Compose configuration +└── Makefile # Make commands +``` - ```sh - cp web/app/composer.json.dist web/app/composer.json - ``` +## 🔐 SSL Configuration -2. Start the application : +To enable HTTPS, follow these steps: - ```sh - docker-compose up -d - ``` +```bash +# Generate self-signed certificates +make gen-certs - **Please wait this might take a several minutes...** +# Enable SSL in Nginx configuration +make enable-ssl +``` - ```sh - docker-compose logs -f # Follow log output - ``` +You can then access your site via HTTPS at [https://localhost:3000](https://localhost:3000). + +The SSL certificates are customizable through environment variables: + +| Variable | Description | Default | +|--------------------|------------------------------------|------------------| +| NGINX_SSL_COUNTRY | Country code | US | +| NGINX_SSL_STATE | State/Province | State | +| NGINX_SSL_LOCALITY | City | City | +| NGINX_SSL_ORGANIZATION | Organization name | Organization | +| NGINX_SSL_UNIT | Organizational unit | IT | +| NGINX_SSL_EMAIL | Contact email | admin@example.com| +| NGINX_SSL_DAYS | Certificate validity in days | 365 | +| NGINX_SSL_KEY_SIZE | RSA key size in bits | 4096 | + +## 🛠️ Available Commands + +The Makefile provides many helpful commands: + +### Environment Management + +| Command | Description | +|-----------|-----------------------------------------------| +| init | Initialize the project | +| dev | Set up development environment | +| prod | Set up production environment | +| start | Start all services | +| stop | Stop all services | +| restart | Restart all services | +| status | Show service status | +| logs | View and follow logs | +| clean | Clean project data (reset to initial state) | +| clean-all | Clean all data including volumes | + +### Development Tools + +| Command | Description | +|-------------------|----------------------------------------------| +| composer-install | Install PHP dependencies | +| composer-update | Update PHP dependencies | +| composer-autoload | Update the autoloader | +| composer-script | Run custom scripts defined in composer.json | +| php-connect | Open an interactive shell in PHP container | +| test | Run tests | +| code-sniff | Check code style with PHP_CodeSniffer | +| phpmd | Analyze code with PHP Mess Detector | +| apidocs-generate | Generate API documentation | +| apidocs-serve | Serve the API documentation via web server | +| apidocs | Generate and serve API documentation | +| gen-certs | Generate SSL certificates | +| enable-ssl | Enable SSL in Nginx configuration | + +### Database Management + +| Command | Description | +|------------------|---------------------------------------| +| db-dump | Backup all databases | +| db-restore | Restore database from backup | +| db-connect | Connect to MySQL shell | + +### Framework Installation + +| Command | Description | +|-------------------|-------------------------------| +| install-symfony | Install Symfony framework | +| install-laravel | Install Laravel framework | + +Run `make help` to see all available commands. + +## PHP Frameworks Support + +This environment supports popular PHP frameworks out of the box. For the best experience with frameworks, follow these recommendations: + +### Recommended Workflow + +1. **First decide** whether you'll use a framework or the default application +2. **Configure your environment** (development or production) +3. **Install your framework** if needed +4. **Modify your .env file** to point to your framework + +### Installing Symfony + +```bash +# First, configure your environment +make dev # or make prod + +# Then, install Symfony +make install-symfony + +# Finally, modify your .env file to use Symfony +# APP_WORKSPACE=symfony +# APP_PUBLIC_DIR=symfony-app/public + +# Restart the containers +make restart +``` -3. Open your favorite browser : +### Installing Laravel - * [http://localhost:8000](http://localhost:8000/) - * [https://localhost:3000](https://localhost:3000/) ([HTTPS](#configure-nginx-with-ssl-certificates) not configured by default) - * [http://localhost:8080](http://localhost:8080/) PHPMyAdmin (username: dev, password: dev) +```bash +# Follow the same approach +make dev # or make prod +make install-laravel -4. Stop and clear services +# Modify your .env file +# APP_WORKSPACE=laravel +# APP_PUBLIC_DIR=laravel-app/public - ```sh - docker-compose down -v - ``` +make restart +``` -___ +### Adding Support for Other Frameworks -## Use Makefile +If you want to use a framework that's not included in the predefined list, you can add support for it by following these steps: -When developing, you can use [Makefile](https://en.wikipedia.org/wiki/Make_(software)) for doing the following operations : +1. **Create a workspace configuration file** for Nginx: -| Name | Description | -|---------------|----------------------------------------------| -| apidoc | Generate documentation of API | -| clean | Clean directories for reset | -| code-sniff | Check the API with PHP Code Sniffer (`PSR2`) | -| composer-up | Update PHP dependencies with composer | -| docker-start | Create and start containers | -| docker-stop | Stop and clear all services | -| gen-certs | Generate SSL certificates for `nginx` | -| logs | Follow log output | -| mysql-dump | Create backup of all databases | -| mysql-restore | Restore backup of all databases | -| phpmd | Analyse the API with PHP Mess Detector | -| test | Test application with phpunit | +```bash +# Create a new configuration file in the workspace directory +touch etc/nginx/workspace/yourworkspace.conf +``` -### Examples +2. **Add the specific Nginx rules** for your workspace. For example: -Start the application : +```nginx +# CakePHP configuration example +location / { + try_files $uri $uri/ /index.php?$args; +} -```sh -make docker-start +# Deny access to sensitive directories +location ~ ^/(config|tmp|logs) { + deny all; + return 404; +} ``` -Show help : +3. **Install your framework** using Composer: -```sh -make help +```bash +docker-compose exec php bash -c "cd /var/www/html && composer create-project your/framework yourworkspace-app" ``` -___ - -## Use Docker commands +4. **Update your `.env` file** to use the new workspace: -### Installing package with composer - -```sh -docker run --rm -v $(pwd)/web/app:/app composer require symfony/yaml ``` - -### Updating PHP dependencies with composer - -```sh -docker run --rm -v $(pwd)/web/app:/app composer update +APP_WORKSPACE=yourworkspace +APP_PUBLIC_DIR=yourworkspace-app/public ``` -### Generating PHP API documentation +5. **Restart the containers** to apply the changes: -```sh -docker run --rm -v $(pwd):/data phpdoc/phpdoc -i=vendor/ -d /data/web/app/src -t /data/web/app/doc +```bash +make restart ``` -### Testing PHP application with PHPUnit +By following these steps, you can extend the environment to support virtually any PHP workspace or custom application structure. -```sh -docker-compose exec -T php ./app/vendor/bin/phpunit --colors=always --configuration ./app -``` +### Important Note -### Fixing standard code with [PSR2](http://www.php-fig.org/psr/psr-2/) +If you switch between environments using `make dev` or `make prod`, you'll need to reconfigure your workspace-specific variables in your `.env` file, as these commands replace the entire file. -```sh -docker-compose exec -T php ./app/vendor/bin/phpcbf -v --standard=PSR2 ./app/src -``` +## 📊 Database Connection -### Checking the standard code with [PSR2](http://www.php-fig.org/psr/psr-2/) +### Connecting from PHP -```sh -docker-compose exec -T php ./app/vendor/bin/phpcs -v --standard=PSR2 ./app/src +```php + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]; + $pdo = new PDO($dsn, 'dev', 'dev', $options); +} catch (PDOException $e) { + throw new PDOException($e->getMessage(), (int)$e->getCode()); +} ``` -### Analyzing source code with [PHP Mess Detector](https://phpmd.org/) +### Using PHPMyAdmin -```sh -docker-compose exec -T php ./app/vendor/bin/phpmd ./app/src text cleancode,codesize,controversial,design,naming,unusedcode -``` +PHPMyAdmin is available at [http://localhost:8080](http://localhost:8080) in the development environment. -### Checking installed PHP extensions +Default credentials: +- Server: mysql +- Username: dev +- Password: dev -```sh -docker-compose exec php php -m -``` +## 🔧 Advanced Configuration -### Handling database +### Database Initialization -#### MySQL shell access +You can add SQL scripts to `docker/mysql/init/` directory. These scripts will be executed automatically when the MySQL container is first started. -```sh -docker exec -it mysql bash -``` +### Customizing PHP -and +This environment uses separate PHP configuration files for development and production: -```sh -mysql -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASSWORD" -``` +- `etc/php/php.dev.ini`: Development configuration with debug features enabled +- `etc/php/php.prod.ini`: Production configuration optimized for performance and security -#### Creating a backup of all databases +You can customize these files to adjust PHP settings for each environment. The appropriate file is selected based on the `PHP_INI` environment variable. -```sh -mkdir -p data/db/dumps -``` +After changing any settings, restart the containers: -```sh -source .env && docker exec $(docker-compose ps -q mysqldb) mysqldump --all-databases -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASSWORD" > "data/db/dumps/db.sql" +```bash +make restart ``` -#### Restoring a backup of all databases +### Customizing Nginx -```sh -source .env && docker exec -i $(docker-compose ps -q mysqldb) mysql -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASSWORD" < "data/db/dumps/db.sql" -``` - -#### Creating a backup of single database +The Nginx configuration uses a template system with environment variables. Edit `etc/nginx/default.template.conf` to customize the server configuration. -**`Notice:`** Replace "YOUR_DB_NAME" by your custom name. +Framework-specific configurations are stored in `etc/nginx/workspace/` directory. -```sh -source .env && docker exec $(docker-compose ps -q mysqldb) mysqldump -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASSWORD" --databases YOUR_DB_NAME > "data/db/dumps/YOUR_DB_NAME_dump.sql" -``` +### Network Architecture -#### Restoring a backup of single database +This project uses a two-layer network architecture: -```sh -source .env && docker exec -i $(docker-compose ps -q mysqldb) mysql -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASSWORD" < "data/db/dumps/YOUR_DB_NAME_dump.sql" -``` +1. **Frontend Network**: For services that need to be accessible from outside (Nginx, PHPMyAdmin) +2. **Backend Network**: For services that should only communicate internally (PHP, MySQL) +This design improves security by isolating internal services from direct external access. -#### Connecting MySQL from [PDO](http://php.net/manual/en/book.pdo.php) +## 📝 License -```php -getMessage(); - } -?> -``` +This project is licensed under the BSD 3-Clause License. -___ +It allows you to: +- Use the software commercially +- Modify the software +- Distribute the software +- Place warranty on the software +- Use the software privately -## Help us +The only requirements are: +- Include the copyright notice +- Include the license text +- Not use the author's name to promote derived products without permission -Any thought, feedback or (hopefully not!) \ No newline at end of file +For more details, see the LICENSE file in the project repository. \ No newline at end of file diff --git a/doc/configure-cacert-for-local-macosx.md b/doc/configure-cacert-for-local-macosx.md deleted file mode 100644 index 5af87dbfd..000000000 --- a/doc/configure-cacert-for-local-macosx.md +++ /dev/null @@ -1,26 +0,0 @@ -# Configure Local CA CERT with MacOS - -## 1. The warning you receive while developing locally. - -![Warning](images/cacert-1-warning.png) - -## 2. Open the keychain app. - -![Open Keychain](images/cacert-2-open-keychain.png) - -## 3. Use File --> Import to add the ca cert you've already created. - -![Add CA Cert](images/cacert-3-add-cacert-file-import.png) - -## 4. Once added, locate it via the search box. - -![Localhost Search Box](images/cacert-4-locate-cert.png) - -## 5. Set to always trust. - -![Trust The Cert](images/cacert-5-set-to-always-trust.png) - -## 6. Reload the webpage. - -![The Results](images/cacert-6-reload-page.png) - diff --git a/doc/images/cacert-1-warning.png b/doc/images/cacert-1-warning.png deleted file mode 100644 index 2a1365b65..000000000 Binary files a/doc/images/cacert-1-warning.png and /dev/null differ diff --git a/doc/images/cacert-2-open-keychain.png b/doc/images/cacert-2-open-keychain.png deleted file mode 100644 index 7a90788be..000000000 Binary files a/doc/images/cacert-2-open-keychain.png and /dev/null differ diff --git a/doc/images/cacert-3-add-cacert-file-import.png b/doc/images/cacert-3-add-cacert-file-import.png deleted file mode 100644 index f7dea1fbb..000000000 Binary files a/doc/images/cacert-3-add-cacert-file-import.png and /dev/null differ diff --git a/doc/images/cacert-4-locate-cert.png b/doc/images/cacert-4-locate-cert.png deleted file mode 100644 index 4031a8a5e..000000000 Binary files a/doc/images/cacert-4-locate-cert.png and /dev/null differ diff --git a/doc/images/cacert-5-set-to-always-trust.png b/doc/images/cacert-5-set-to-always-trust.png deleted file mode 100644 index 6e7fee09d..000000000 Binary files a/doc/images/cacert-5-set-to-always-trust.png and /dev/null differ diff --git a/doc/images/cacert-6-reload-page.png b/doc/images/cacert-6-reload-page.png deleted file mode 100644 index 3bbeb4201..000000000 Binary files a/doc/images/cacert-6-reload-page.png and /dev/null differ diff --git a/doc/images/ps-mac-php-cli-add-interpreter.png b/doc/images/ps-mac-php-cli-add-interpreter.png deleted file mode 100644 index 46b5aca76..000000000 Binary files a/doc/images/ps-mac-php-cli-add-interpreter.png and /dev/null differ diff --git a/doc/images/ps-mac-php-interpreter.png b/doc/images/ps-mac-php-interpreter.png deleted file mode 100644 index 48ba727cc..000000000 Binary files a/doc/images/ps-mac-php-interpreter.png and /dev/null differ diff --git a/doc/images/ps-mac-php-phpunit-config.png b/doc/images/ps-mac-php-phpunit-config.png deleted file mode 100644 index fb64c33e7..000000000 Binary files a/doc/images/ps-mac-php-phpunit-config.png and /dev/null differ diff --git a/doc/images/ps-mac-php-phpunit-demo.png b/doc/images/ps-mac-php-phpunit-demo.png deleted file mode 100644 index c76b06d87..000000000 Binary files a/doc/images/ps-mac-php-phpunit-demo.png and /dev/null differ diff --git a/doc/images/ps-mac-php-phpunit.png b/doc/images/ps-mac-php-phpunit.png deleted file mode 100644 index a9bff94d3..000000000 Binary files a/doc/images/ps-mac-php-phpunit.png and /dev/null differ diff --git a/doc/images/ps-mac-php-xdebug-demo.png b/doc/images/ps-mac-php-xdebug-demo.png deleted file mode 100644 index 9d520deac..000000000 Binary files a/doc/images/ps-mac-php-xdebug-demo.png and /dev/null differ diff --git a/doc/images/ps-mac-php-xdebug-proxy.png b/doc/images/ps-mac-php-xdebug-proxy.png deleted file mode 100644 index 6c88dca09..000000000 Binary files a/doc/images/ps-mac-php-xdebug-proxy.png and /dev/null differ diff --git a/doc/images/ps-mac-php-xdebug-server.png b/doc/images/ps-mac-php-xdebug-server.png deleted file mode 100644 index 77014ce5f..000000000 Binary files a/doc/images/ps-mac-php-xdebug-server.png and /dev/null differ diff --git a/doc/images/ps-mac-php-xdebug.png b/doc/images/ps-mac-php-xdebug.png deleted file mode 100644 index 08da762c7..000000000 Binary files a/doc/images/ps-mac-php-xdebug.png and /dev/null differ diff --git a/doc/phpstorm-macosx.md b/doc/phpstorm-macosx.md deleted file mode 100644 index 177946d9d..000000000 --- a/doc/phpstorm-macosx.md +++ /dev/null @@ -1,71 +0,0 @@ -# Configure PHPStorm with MacOS - -Inspired from this following links : - -- [Running PHPUnit Tests in PhpStorm with Docker](https://www.youtube.com/watch?v=I7aGWO6K3Ho) -- [All hail Xdebug and lets let var dump die](http://jamescowie.me/blog/2016/12/all-hail-xdebug-and-lets-let-var-dump-die/) - -## Edit PHP configuration - -![PHP CLI Interpreter](images/ps-mac-php-interpreter.png) - -## Add a PHP interpreter - -![Add PHP CLI Interpreter](images/ps-mac-php-cli-add-interpreter.png) - -## Configure PHPUnit - -![PHPUnit](images/ps-mac-php-phpunit.png) - -### Add test configuration - -![PHPUnit Config](images/ps-mac-php-phpunit-config.png) - -### PHPUnit Demo - -![PHPUnit Demo](images/ps-mac-php-phpunit-demo.png) - -## Configure XDebug - -### Edit `etc/php.ini` file - -Add this following lines : - -```sh -[xdebug] -xdebug.remote_host = 10.254.254.254 -xdebug.remote_port = 9000 -xdebug.remote_autostart=1 -xdebug.idekey = PHPSTORM -xdebug.remote_enable = 1 -xdebug.remote_connect_back = 0 -xdebug.profiler_enable = 1 -``` - -### Check Debug section - -![Xdebug](images/ps-mac-php-xdebug.png) - -### Add a debug server - -![XDebug Server](images/ps-mac-php-xdebug-server.png) - -### Configure XDebug Proxy - -Create an IP Alias : - -```sh -sudo ifconfig en0 alias 10.254.254.254 255.255.255.0 -``` - -![Xdebug Proxy](images/ps-mac-php-xdebug-proxy.png) - -To delete an IP Alias : - -```sh -sudo ifconfig en0 -alias 10.254.254.254 -``` - -### XDebug Demo - -![XDebug Demo](images/ps-mac-php-xdebug-demo.png) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b30cd5728..65c03ef17 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,56 +1,134 @@ -version: '3' +version: '3.8' + +networks: + frontend-network: + driver: bridge + backend-network: + driver: bridge + services: + mysqldb: + image: mysql:${MYSQL_VERSION} + container_name: ${MYSQL_HOST} + restart: always + environment: + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + ports: + - "${MYSQL_PORT:-8989}:3306" + volumes: + - mysql_data:/var/lib/mysql + - ./docker/mysql/init:/docker-entrypoint-initdb.d + networks: + - backend-network + healthcheck: + test: [ "CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}" ] + interval: 5s + timeout: 5s + retries: 5 + start_period: 30s + web: image: nginx:alpine volumes: + - "./etc/nginx/workspace:/etc/nginx/conf.d/workspace" - "./etc/nginx/default.conf:/etc/nginx/conf.d/default.conf" + - "./etc/nginx/default.template.conf:/etc/nginx/conf.d/default.template" - "./etc/ssl:/etc/ssl" - "./web:/var/www/html" - - "./etc/nginx/default.template.conf:/etc/nginx/conf.d/default.template" ports: - - "8000:80" - - "3000:443" + - "${NGINX_PORT:-8000}:80" + - "${NGINX_SSL_PORT:-3000}:443" environment: - NGINX_HOST=${NGINX_HOST} - command: /bin/sh -c "envsubst '$$NGINX_HOST' < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" + - APP_WORKSPACE=${APP_WORKSPACE:-default} + - APP_DIR=${APP_DIR:-app} + - APP_PUBLIC_DIR=${APP_DIR:-app}/public + - NGINX_WORKSPACE_DIR=${NGINX_WORKSPACE_DIR:-workspace} + command: /bin/sh -c "envsubst '$$NGINX_HOST $$APP_WORKSPACE $$APP_PUBLIC_DIR $$NGINX_WORKSPACE_DIR' < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" restart: always depends_on: - php - mysqldb + networks: + - frontend-network + - backend-network + healthcheck: + test: [ "CMD", "curl", "-f", "http://localhost" ] + interval: 10s + timeout: 3s + retries: 3 + php: - image: nanoninja/php-fpm:${PHP_VERSION} + build: + context: ./docker/php + args: + PHP_VERSION: ${PHP_VERSION} + PHP_TARGET: ${PHP_TARGET:-dev} restart: always volumes: - - "./etc/php/php.ini:/usr/local/etc/php/conf.d/php.ini" + - "./etc/php/${PHP_INI:-php.dev.ini}:/usr/local/etc/php/conf.d/99-custom.ini" - "./web:/var/www/html" - composer: - image: "composer" - volumes: - - "./web/app:/app" - command: install + networks: + - backend-network + healthcheck: + test: [ "CMD", "php-fpm", "-t" ] + interval: 10s + timeout: 5s + retries: 3 + myadmin: image: phpmyadmin/phpmyadmin container_name: phpmyadmin ports: - - "8080:80" + - "${PHPMYADMIN_PORT:-8080}:80" environment: - PMA_ARBITRARY=1 - PMA_HOST=${MYSQL_HOST} + - PMA_USER=${PHPMYADMIN_USER:-root} + - PMA_PASSWORD=${PHPMYADMIN_PASSWORD:-${MYSQL_ROOT_PASSWORD}} + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - UPLOAD_LIMIT=${PHPMYADMIN_UPLOAD_LIMIT:-100M} restart: always depends_on: - - mysqldb - mysqldb: - image: mysql:${MYSQL_VERSION} - container_name: ${MYSQL_HOST} - restart: always - env_file: - - ".env" - environment: - - MYSQL_DATABASE=${MYSQL_DATABASE} - - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - - MYSQL_USER=${MYSQL_USER} - - MYSQL_PASSWORD=${MYSQL_PASSWORD} + mysqldb: + condition: service_healthy + networks: + - frontend-network + - backend-network + profiles: + - ${PHPMYADMIN_PROFILE:-dev} + + mailhog: + image: mailhog/mailhog ports: - - "8989:3306" + - "${MAILHOG_SMTP_PORT:-1025}:1025" # SMTP port for sending emails + - "${MAILHOG_UI_PORT:-8025}:8025" # Web interface for viewing emails + environment: + - MH_SMTP_BIND_ADDR=0.0.0.0:1025 # Binding address for the SMTP server + - MH_API_BIND_ADDR=0.0.0.0:8025 # Binding address for the API + - MH_UI_BIND_ADDR=0.0.0.0:8025 # Binding address for the user interface + - MH_STORAGE=${MAILHOG_STORAGE:-memory} # Storage method (memory, mongodb) + - MH_HOSTNAME=${MAILHOG_HOSTNAME:-mailhog} # Hostname to use for EHLO/HELO links + - MH_CORS_ORIGIN=${MAILHOG_CORS_ORIGIN:-*} # CORS Configuration + networks: + - backend-network + profiles: + - ${MAILHOG_PROFILE:-dev} + + apidocs: + image: nginx:alpine volumes: - - "./data/db/mysql:/var/lib/mysql" \ No newline at end of file + - "./docs/api/html:/usr/share/nginx/html:ro" + ports: + - "${APIDOCS_PORT:-8081}:80" + networks: + - frontend-network + profiles: + - ${APIDOCS_PROFILE:-dev} + +volumes: + mysql_data: + name: ${APP_NAME:-docker_nginx_php_mysql}_mysql_data diff --git a/docker/mysql/init/01-create-tables.sql b/docker/mysql/init/01-create-tables.sql new file mode 100644 index 000000000..ebddd6d2a --- /dev/null +++ b/docker/mysql/init/01-create-tables.sql @@ -0,0 +1,27 @@ +-- Example initialization script +-- This will run when the MySQL container is first started + +-- Use database +-- USE test; + +-- Create a sample table +-- CREATE TABLE IF NOT EXISTS sample_table ( +-- id INT AUTO_INCREMENT PRIMARY KEY, +-- name VARCHAR(255) NOT NULL, +-- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Insert some sample data +-- INSERT INTO sample_table (name) VALUES +-- ('Example 1'), +-- ('Example 2'), +-- ('Example 3'); + +-- Create a user table +-- CREATE TABLE IF NOT EXISTS users ( +-- id INT AUTO_INCREMENT PRIMARY KEY, +-- username VARCHAR(50) NOT NULL UNIQUE, +-- email VARCHAR(100) NOT NULL UNIQUE, +-- password VARCHAR(255) NOT NULL, +-- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile new file mode 100644 index 000000000..b46b4d8c3 --- /dev/null +++ b/docker/php/Dockerfile @@ -0,0 +1,105 @@ +# docker/php/Dockerfile +ARG PHP_VERSION + +# Base PHP image with essential extensions +FROM php:${PHP_VERSION}-fpm AS php-base + +LABEL maintainer="Vincent Letourneau " +LABEL version="2.0.0" +LABEL description="PHP-FPM image for docker-nginx-php-mysql with essential extensions" + +# Install essential dependencies +RUN apt-get update && apt-get upgrade -y \ + && apt-get install -y \ + g++ \ + libzip-dev \ + libpng-dev \ + libjpeg62-turbo-dev \ + libfreetype6-dev \ + libicu-dev \ + libssl-dev \ + libxslt-dev \ + && docker-php-ext-install -j$(nproc) \ + bcmath \ + calendar \ + exif \ + mysqli \ + opcache \ + pdo_mysql \ + xsl \ + zip \ + && docker-php-ext-configure gd --with-freetype --with-jpeg \ + && docker-php-ext-install -j$(nproc) gd \ + && docker-php-ext-configure intl \ + && docker-php-ext-install -j$(nproc) intl + +# Install Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# Optimized PHP configuration for production +RUN { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + echo 'opcache.enable_cli=1'; \ + } > /usr/local/etc/php/conf.d/opcache-recommended.ini + +# Cleanup +RUN apt-get remove -y g++ \ + && apt-get autoremove --purge -y \ + && apt-get autoclean -y && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /tmp/* /var/tmp/* + +# Set working directory +WORKDIR /var/www/html + +ARG PHP_TARGET + +# If building for development, add development extensions +RUN if [ "$PHP_TARGET" = "dev" ]; then \ + apt-get update && apt-get install -y \ + libbz2-dev \ + libc-client-dev \ + libcurl4-gnutls-dev \ + libedit-dev \ + libkrb5-dev \ + libldap2-dev \ + libldb-dev \ + libmagickwand-dev \ + libmcrypt-dev \ + libmemcached-dev \ + libpq-dev \ + libsqlite3-dev \ + memcached \ + wget \ + unzip \ + && docker-php-ext-install -j$(nproc) \ + bz2 \ + gettext \ + pdo_pgsql \ + pgsql \ + soap \ + sockets \ + && PHP_OPENSSL=yes docker-php-ext-configure imap --with-kerberos --with-imap-ssl \ + && docker-php-ext-install -j$(nproc) imap \ + # && pecl install imagick && docker-php-ext-enable imagick \ + && docker-php-ext-configure ldap \ + && docker-php-ext-install ldap \ + && pecl install xdebug && docker-php-ext-enable xdebug \ + && pecl install memcached && docker-php-ext-enable memcached \ + && pecl install mongodb && docker-php-ext-enable mongodb \ + && pecl install redis && docker-php-ext-enable redis \ + && docker-php-source delete \ + && apt-get remove -y wget \ + && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /tmp/* /var/tmp/* ; \ +else \ + echo "Building production image without development tools."; \ +fi + +# Default command +CMD ["php-fpm"] \ No newline at end of file diff --git a/docker/ssl/Dockerfile b/docker/ssl/Dockerfile new file mode 100644 index 000000000..0f3814420 --- /dev/null +++ b/docker/ssl/Dockerfile @@ -0,0 +1,23 @@ +FROM alpine:3.18 + +# Install necessary packages +RUN apk add --no-cache openssl + +WORKDIR /certificates + +# Environment variables with defaults +ENV SERVER=localhost \ + CERT_EXPIRY=365 \ + KEY_SIZE=4096 \ + COUNTRY=US \ + STATE=State \ + LOCALITY=City \ + ORGANIZATION=Organization \ + ORGANIZATIONAL_UNIT=IT \ + EMAIL=admin@example.com + +# Script to generate certificates +COPY generate-cert.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/generate-cert.sh + +ENTRYPOINT ["/usr/local/bin/generate-cert.sh"] \ No newline at end of file diff --git a/docker/ssl/generate-cert.sh b/docker/ssl/generate-cert.sh new file mode 100644 index 000000000..6e30049a1 --- /dev/null +++ b/docker/ssl/generate-cert.sh @@ -0,0 +1,59 @@ +#!/bin/sh +set -e + +echo "Generating SSL certificate for $SERVER" + +# Create config file for certificate +cat > openssl.cnf << EOF +[req] +default_bits = $KEY_SIZE +default_md = sha256 +distinguished_name = req_distinguished_name +req_extensions = v3_req +prompt = no + +[req_distinguished_name] +countryName = $COUNTRY +stateOrProvinceName = $STATE +localityName = $LOCALITY +organizationName = $ORGANIZATION +organizationalUnitName = $ORGANIZATIONAL_UNIT +commonName = $SERVER +emailAddress = $EMAIL + +[v3_req] +subjectAltName = @alt_names +keyUsage = digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth + +[alt_names] +DNS.1 = $SERVER +DNS.2 = www.$SERVER +EOF + +# Generate private key +openssl genrsa -out server.key $KEY_SIZE + +# Generate certificate signing request +openssl req -new -key server.key -out server.csr -config openssl.cnf + +# Generate self-signed certificate +openssl x509 -req -days $CERT_EXPIRY -in server.csr -signkey server.key -out server.crt \ + -extensions v3_req -extfile openssl.cnf + +# Generate PEM file (combined certificate and key) +cat server.crt server.key > server.pem + +# Set permissions +chmod 644 server.crt server.key server.pem + +echo "Certificate files generated:" +echo " - server.key: Private key" +echo " - server.crt: Certificate" +echo " - server.pem: Combined certificate and key" +echo " - server.csr: Certificate signing request (can be deleted)" + +# Clean up +rm server.csr openssl.cnf + +echo "SSL certificate generation completed." \ No newline at end of file diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 000000000..dd470135f --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,506 @@ +# Docker Nginx PHP MySQL - Command Line Reference + +This document provides a comprehensive reference of all available commands in the Docker Nginx PHP MySQL environment. These commands can be executed using the `make` utility or directly with Docker and Docker Compose commands. + +## Environment Variables for Manual Commands + +When running the commands manually without Make, you can use these variables for consistency: + +```bash +# Core directories and settings +WEB_ROOT="./web" +APP_DIR="app" # Change this to your application directory (e.g., symfony-app, laravel-app) +APP_ROOT="${WEB_ROOT}/${APP_DIR}" +MYSQL_DUMPS_DIR="data/db/dumps" +COMPOSE_PROJECT_NAME="docker_nginx_php_mysql" # Change to match your .env configuration + +# Container information +PHP_CONTAINER="php" +MYSQL_CONTAINER=$(docker compose ps -q mysqldb 2>/dev/null) +``` + +## Environment Management Commands + +These commands help you manage your development and production environments. + +### `init` + +Initializes the project by setting up the environment and installing dependencies. + +```bash +# Using make +make init + +# Manual alternative +cp .env.dev .env +mkdir -p ${APP_ROOT} +cp ${WEB_ROOT}/composer.json.dist ${APP_ROOT}/composer.json 2>/dev/null || echo "{}" > ${APP_ROOT}/composer.json +docker compose up -d +docker compose exec -T ${PHP_CONTAINER} composer install -d /var/www/html/${APP_DIR} +``` + +### `dev` + +Configures the environment for development. + +```bash +# Using make +make dev + +# Manual alternative +cp .env.dev .env +docker compose down +docker compose --profile dev up -d +``` + +### `prod` + +Configures the environment for production. + +```bash +# Using make +make prod + +# Manual alternative +cp .env.prod .env +docker compose down +docker compose up -d +``` + +### `start` + +Starts all services defined in the Docker Compose file. + +```bash +# Using make +make start + +# Manual alternative +# For development environment (with PHPMyAdmin) +docker compose --profile dev up -d +# For production environment (without PHPMyAdmin) +docker compose up -d +``` + +### `stop` + +Stops all services and removes containers. + +```bash +# Using make +make stop + +# Manual alternative +docker compose down +``` + +### `restart` + +Restarts all services. + +```bash +# Using make +make restart + +# Manual alternative +docker compose down +docker compose up -d +``` + +### `status` + +Displays the status of all containers. + +```bash +# Using make +make status + +# Manual alternative +docker compose ps +``` + +### `logs` + +Displays and follows log output from all containers. + +```bash +# Using make +make logs + +# Manual alternative +docker compose logs -f +``` + +## PHP Development Commands + +These commands help with PHP dependency management and code quality. + +### `composer-install` + +Installs PHP dependencies using Composer. + +```bash +# Using make +make composer-install + +# Manual alternative +docker compose exec -T ${PHP_CONTAINER} composer install -d /var/www/html/${APP_DIR} +``` + +### `composer-update` + +Updates PHP dependencies to their latest versions. + +```bash +# Using make +make composer-update + +# Manual alternative +docker compose exec -T ${PHP_CONTAINER} composer update -d /var/www/html/${APP_DIR} +``` + +### `composer-autoload` + +Updates the Composer autoloader. + +```bash +# Using make +make composer-autoload + +# Manual alternative +docker compose exec -T ${PHP_CONTAINER} composer dump-autoload -d /var/www/html/${APP_DIR} +``` + +### `composer-script` + +Runs a composer script with optional arguments. + +```bash +# Using make with arguments +make composer-script SCRIPT=test ARGS="--filter=TestClass" + +# Manual alternative +docker compose exec -T ${PHP_CONTAINER} composer run-script test --filter=TestClass -d /var/www/html/${APP_DIR} +``` + +### `test` + +Runs PHPUnit tests. + +```bash +# Using make +make test + +# Manual alternative +docker compose exec -T ${PHP_CONTAINER} ./${APP_DIR}/vendor/bin/phpunit --colors=always --configuration ./${APP_DIR}/ +``` + +### `code-sniff` + +Checks the code against PSR2 coding standards. + +```bash +# Using make +make code-sniff + +# Manual alternative +docker compose exec -T ${PHP_CONTAINER} ./${APP_DIR}/vendor/bin/phpcs -v --standard=PSR2 ${APP_DIR}/src +``` + +### `phpmd` + +Analyzes code with PHP Mess Detector. + +```bash +# Using make +make phpmd + +# Manual alternative +docker compose exec -T ${PHP_CONTAINER} ./${APP_DIR}/vendor/bin/phpmd ./${APP_DIR}/src text cleancode,codesize,controversial,design,naming,unusedcode +``` + +## API Documentation Commands + +These commands help generate and serve API documentation. + +### `apidocs-generate` + +Generates API documentation using phpDocumentor. + +```bash +# Using make +make apidocs-generate + +# Manual alternative +mkdir -p ./docs/api/html +docker run --rm -v $(pwd):/data phpdoc/phpdoc -i=vendor/ -d /data/web/${APP_DIR}/src -t /data/docs/api/html +chown -R $(id -u):$(id -g) ./docs/api +``` + +### `apidocs-serve` + +Starts a web server to view the generated API documentation. + +```bash +# Using make +make apidocs-serve + +# Manual alternative +docker compose --profile dev up -d apidocs +echo "API documentation available at http://localhost:8081" +``` + +### `apidocs` + +Generates and serves API documentation in one command. + +```bash +# Using make +make apidocs + +# Manual alternative +mkdir -p ./docs/api/html +docker run --rm -v $(pwd):/data phpdoc/phpdoc -i=vendor/ -d /data/web/${APP_DIR}/src -t /data/docs/api/html +chown -R $(id -u):$(id -g) ./docs/api +docker compose --profile dev up -d apidocs +echo "API documentation available at http://localhost:8081" +``` + +## Container Access Commands + +These commands provide direct access to container shells. + +### `php-connect` + +Opens a shell in the PHP container. + +```bash +# Using make +make php-connect + +# Manual alternative +docker compose exec -it ${PHP_CONTAINER} bash +``` + +### `db-connect` + +Opens a MySQL shell. + +```bash +# Using make +make db-connect + +# Manual alternative +docker exec -it $(docker compose ps -q mysqldb) mysql -uroot -p$(grep MYSQL_ROOT_PASSWORD .env | cut -d '=' -f2) +``` + +## Database Commands + +These commands help manage the MySQL database. + +### `db-dump` + +Creates a backup of all databases. + +```bash +# Using make +make db-dump + +# Manual alternative +mkdir -p ${MYSQL_DUMPS_DIR} +MYSQL_ROOT_PASSWORD=$(grep MYSQL_ROOT_PASSWORD .env | cut -d '=' -f2) +docker exec $(docker compose ps -q mysqldb) mysqldump --all-databases -u"root" -p"${MYSQL_ROOT_PASSWORD}" > ${MYSQL_DUMPS_DIR}/db.sql +chown -R $(id -u):$(id -g) ${MYSQL_DUMPS_DIR} +``` + +### `db-restore` + +Restores a backup of all databases. + +```bash +# Using make +make db-restore + +# Manual alternative +if [ -f "${MYSQL_DUMPS_DIR}/db.sql" ]; then + MYSQL_ROOT_PASSWORD=$(grep MYSQL_ROOT_PASSWORD .env | cut -d '=' -f2) + docker exec -i $(docker compose ps -q mysqldb) mysql -u"root" -p"${MYSQL_ROOT_PASSWORD}" < ${MYSQL_DUMPS_DIR}/db.sql +else + echo "Backup file not found at ${MYSQL_DUMPS_DIR}/db.sql" +fi +``` + +## Framework Installation Commands + +These commands install popular PHP frameworks. + +### `install-symfony` + +Installs the Symfony framework. + +```bash +# Using make +make install-symfony + +# Manual alternative +if [ -d "${WEB_ROOT}/symfony-app" ]; then + echo "Directory 'symfony-app' already exists!" + echo "Please remove or rename the existing directory before installing Symfony." + exit 1 +fi +docker compose exec -T ${PHP_CONTAINER} bash -c "cd /var/www/html && composer create-project symfony/skeleton symfony-app" +echo "Symfony installed in ./web/symfony-app!" +echo "To configure your environment for Symfony, update these variables in .env:" +echo "APP_WORKSPACE=symfony" +echo "APP_DIR=symfony-app" +echo "Then restart the containers with: docker compose restart" +``` + +### `install-laravel` + +Installs the Laravel framework. + +```bash +# Using make +make install-laravel + +# Manual alternative +if [ -d "${WEB_ROOT}/laravel-app" ]; then + echo "Directory 'laravel-app' already exists!" + echo "Please remove or rename the existing directory before installing Laravel." + exit 1 +fi +docker compose exec -T ${PHP_CONTAINER} bash -c "cd /var/www/html && composer create-project laravel/laravel laravel-app" +echo "Laravel installed in ./web/laravel-app!" +echo "To configure your environment for Laravel, update these variables in .env:" +echo "APP_WORKSPACE=laravel" +echo "APP_DIR=laravel-app" +echo "Then restart the containers with: docker compose restart" +``` + +## Utility Commands + +These commands provide various utilities. + +### `env-clean` + +Cleans environment resources. + +```bash +# Using make +make env-clean + +# Manual alternative +docker container prune -f --filter "label=com.docker.compose.project=${COMPOSE_PROJECT_NAME}" +docker network prune -f --filter "label=com.docker.compose.project=${COMPOSE_PROJECT_NAME}" +rm -rf .phpdoc +rm -rf etc/ssl/* +``` + +### `env-reset` + +Resets the environment completely, including volumes. + +```bash +# Using make +make env-reset + +# Manual alternative +docker compose down +docker container prune -f --filter "label=com.docker.compose.project=${COMPOSE_PROJECT_NAME}" +docker network prune -f --filter "label=com.docker.compose.project=${COMPOSE_PROJECT_NAME}" +docker volume rm $(docker volume ls -q -f name=${COMPOSE_PROJECT_NAME}) 2>/dev/null || true +rm -rf .phpdoc +rm -rf etc/ssl/* +rm -rf ${MYSQL_DUMPS_DIR}/* +``` + +### `gen-certs` + +Generates SSL certificates. + +```bash +# Using make +make gen-certs + +# Manual alternative +docker build -t ssl-generator docker/ssl +NGINX_HOST=$(grep NGINX_HOST .env | cut -d '=' -f2) +NGINX_SSL_COUNTRY=$(grep NGINX_SSL_COUNTRY .env | cut -d '=' -f2) +NGINX_SSL_STATE=$(grep NGINX_SSL_STATE .env | cut -d '=' -f2) +NGINX_SSL_LOCALITY=$(grep NGINX_SSL_LOCALITY .env | cut -d '=' -f2) +NGINX_SSL_ORGANIZATION=$(grep NGINX_SSL_ORGANIZATION .env | cut -d '=' -f2) +NGINX_SSL_UNIT=$(grep NGINX_SSL_UNIT .env | cut -d '=' -f2) +NGINX_SSL_EMAIL=$(grep NGINX_SSL_EMAIL .env | cut -d '=' -f2) +NGINX_SSL_DAYS=$(grep NGINX_SSL_DAYS .env | cut -d '=' -f2) +NGINX_SSL_KEY_SIZE=$(grep NGINX_SSL_KEY_SIZE .env | cut -d '=' -f2) + +docker run --rm -v $(pwd)/etc/ssl:/certificates \ + -e SERVER=${NGINX_HOST} \ + -e COUNTRY=${NGINX_SSL_COUNTRY} \ + -e STATE=${NGINX_SSL_STATE} \ + -e LOCALITY=${NGINX_SSL_LOCALITY} \ + -e ORGANIZATION=${NGINX_SSL_ORGANIZATION} \ + -e ORGANIZATIONAL_UNIT=${NGINX_SSL_UNIT} \ + -e EMAIL=${NGINX_SSL_EMAIL} \ + -e CERT_EXPIRY=${NGINX_SSL_DAYS} \ + -e KEY_SIZE=${NGINX_SSL_KEY_SIZE} \ + ssl-generator +chown -R $(id -u):$(id -g) $(pwd)/etc/ssl +``` + +### `enable-ssl` + +Enables SSL in the Nginx configuration. + +```bash +# Using make +make enable-ssl + +# Manual alternative +docker run --rm -v $(pwd)/etc/nginx:/etc/nginx alpine:latest \ + sh -c 'apk add --no-cache sed && sed -i "/^# server {/,/^# }/ s/^# //" /etc/nginx/default.template.conf && sed -i "/^#[[:space:]]*$/s/^#//" /etc/nginx/default.template.conf' +docker compose restart +NGINX_HOST=$(grep NGINX_HOST .env | cut -d '=' -f2) +echo "SSL has been enabled. Access your site at https://${NGINX_HOST}:3000" +``` + +### `xdebug-check` + +Checks Xdebug configuration. + +```bash +# Using make +make xdebug-check + +# Manual alternative +docker compose exec -T ${PHP_CONTAINER} php -v +docker compose exec -T ${PHP_CONTAINER} php -i | grep -i xdebug +``` + +### `xdebug-restart` + +Restarts the PHP container with Xdebug. + +```bash +# Using make +make xdebug-restart + +# Manual alternative +docker compose restart php +echo "PHP container restarted!" +docker compose exec -T ${PHP_CONTAINER} php -v | grep -i xdebug +``` + +## Notes for Windows Users + +If you're using Windows and don't have access to the `make` command, you can: + +1. Install Make for Windows through [GnuWin32](http://gnuwin32.sourceforge.net/packages/make.htm) +2. Use WSL (Windows Subsystem for Linux) +3. Use the manual alternative commands listed above +4. Use Git Bash which provides a Unix-like terminal + +For Windows users using Command Prompt or PowerShell, you may need to adapt some commands, particularly those using environment variables and paths. + +For specific Windows issues or if you encounter any problems, please refer to the project's GitHub issue tracker. diff --git a/etc/nginx/default.conf b/etc/nginx/default.conf index 17db04a90..e69de29bb 100644 --- a/etc/nginx/default.conf +++ b/etc/nginx/default.conf @@ -1,77 +0,0 @@ -# Nginx configuration - -server { - listen 80 default_server; - listen [::]:80 default_server; - server_name localhost; - - index index.php index.html; - error_log /var/log/nginx/error.log; - access_log /var/log/nginx/access.log; - root /var/www/html/public; - - set $virtualdir ""; - set $realdir ""; - - if ($request_uri ~ ^/([^/]*)/.*$ ) { - set $virtualdir /$1; - } - - if (-d "$document_root$virtualdir") { - set $realdir "${virtualdir}"; - } - - location / { - try_files $uri $uri/ $realdir/index.php?$args; - } - location ~ \.php$ { - try_files $uri =404; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass php:9000; - fastcgi_index index.php; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - } -} - -# server { -# server_name localhost; - -# listen 443 ssl; -# fastcgi_param HTTPS on; - -# ssl_certificate /etc/ssl/server.pem; -# ssl_certificate_key /etc/ssl/server.key; -# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; - -# index index.php index.html; -# error_log /var/log/nginx/error.log; -# access_log /var/log/nginx/access.log; -# root /var/www/html/public; - -# set $virtualdir ""; -# set $realdir ""; - -# if ($request_uri ~ ^/([^/]*)/.*$ ) { -# set $virtualdir /$1; -# } - -# if (-d "$document_root$virtualdir") { -# set $realdir "${virtualdir}"; -# } - -# location / { -# try_files $uri $uri/ $realdir/index.php?$args; -# } - -# location ~ \.php$ { -# try_files $uri =404; -# fastcgi_split_path_info ^(.+\.php)(/.+)$; -# fastcgi_pass php:9000; -# fastcgi_index index.php; -# include fastcgi_params; -# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; -# fastcgi_param PATH_INFO $fastcgi_path_info; -# } -# } diff --git a/etc/nginx/default.template.conf b/etc/nginx/default.template.conf index 3d76e28d9..d71ed55be 100644 --- a/etc/nginx/default.template.conf +++ b/etc/nginx/default.template.conf @@ -1,29 +1,23 @@ # Nginx configuration +# HTTP Server server { listen 80 default_server; listen [::]:80 default_server; server_name ${NGINX_HOST}; - index index.php index.html; - error_log /var/log/nginx/error.log; + # Logging access_log /var/log/nginx/access.log; - root /var/www/html/public; + error_log /var/log/nginx/error.log; - set $virtualdir ""; - set $realdir ""; + # Root directory and index files + root /var/www/html/${APP_PUBLIC_DIR}; + index index.php index.html; - if ($request_uri ~ ^/([^/]*)/.*$ ) { - set $virtualdir /$1; - } + # Workspace specific configuration + include /etc/nginx/conf.d/workspace/${APP_WORKSPACE}.conf; - if (-d "$document_root$virtualdir") { - set $realdir "${virtualdir}"; - } - - location / { - try_files $uri $uri/ $realdir/index.php?$args; - } + # PHP-FPM Configuration location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; @@ -33,38 +27,57 @@ server { fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } + + # Deny access to hidden files + location ~ /\. { + deny all; + } + + # Deny access to specific directories + location ~ ^/(vendor|tests|src|app)/ { + deny all; + return 404; + } + + # Optimize static file serving + location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { + expires 30d; + add_header Cache-Control "public, no-transform"; + } } +# HTTPS Server (uncomment to enable SSL) # server { -# server_name ${NGINX_HOST}; - # listen 443 ssl; -# fastcgi_param HTTPS on; - -# ssl_certificate /etc/ssl/server.pem; +# listen [::]:443 ssl; +# http2 on; +# +# server_name ${NGINX_HOST}; +# +# # SSL Configuration +# ssl_certificate /etc/ssl/server.crt; # ssl_certificate_key /etc/ssl/server.key; -# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; - +# +# # Modern SSL settings +# ssl_protocols TLSv1.2 TLSv1.3; +# ssl_prefer_server_ciphers on; +# ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; +# ssl_session_cache shared:SSL:10m; +# ssl_session_timeout 1d; +# ssl_session_tickets off; +# +# # Root directory and index files +# root /var/www/html/${APP_PUBLIC_DIR}; # index index.php index.html; -# error_log /var/log/nginx/error.log; +# +# # Logging # access_log /var/log/nginx/access.log; -# root /var/www/html/public; - -# set $virtualdir ""; -# set $realdir ""; - -# if ($request_uri ~ ^/([^/]*)/.*$ ) { -# set $virtualdir /$1; -# } - -# if (-d "$document_root$virtualdir") { -# set $realdir "${virtualdir}"; -# } - -# location / { -# try_files $uri $uri/ $realdir/index.php?$args; -# } - +# error_log /var/log/nginx/error.log; +# +# # Workspace specific configuration +# include /etc/nginx/conf.d/workspace/${APP_WORKSPACE}.conf; +# +# # PHP-FPM Configuration # location ~ \.php$ { # try_files $uri =404; # fastcgi_split_path_info ^(.+\.php)(/.+)$; @@ -73,5 +86,23 @@ server { # include fastcgi_params; # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # fastcgi_param PATH_INFO $fastcgi_path_info; +# fastcgi_param HTTPS on; +# } +# +# # Deny access to hidden files +# location ~ /\. { +# deny all; +# } +# +# # Deny access to specific directories +# location ~ ^/(vendor|tests|src|app)/ { +# deny all; +# return 404; +# } +# +# # Optimize static file serving +# location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { +# expires 30d; +# add_header Cache-Control "public, no-transform"; # } -# } +# } \ No newline at end of file diff --git a/etc/nginx/workspace/default.conf b/etc/nginx/workspace/default.conf new file mode 100644 index 000000000..58d69fea5 --- /dev/null +++ b/etc/nginx/workspace/default.conf @@ -0,0 +1,14 @@ +# Default framework configuration +# Handles standard PHP applications + +# Standard configuration - direct file access +location / { + try_files $uri $uri/ =404; +} + +# Router-based configuration - uncomment to enable +# With this configuration, all requests will be directed to index.php +# if the requested file doesn't exist +# location / { +# try_files $uri $uri/ /index.php$is_args$args; +# } \ No newline at end of file diff --git a/etc/nginx/workspace/laravel.conf b/etc/nginx/workspace/laravel.conf new file mode 100644 index 000000000..2fc020839 --- /dev/null +++ b/etc/nginx/workspace/laravel.conf @@ -0,0 +1,5 @@ +# Laravel framework configuration + +location / { + try_files $uri $uri/ /index.php?$query_string; +} diff --git a/etc/nginx/workspace/symfony.conf b/etc/nginx/workspace/symfony.conf new file mode 100644 index 000000000..81b2cc7c8 --- /dev/null +++ b/etc/nginx/workspace/symfony.conf @@ -0,0 +1,5 @@ +# Symfony framework configuration + +location / { + try_files $uri /index.php$is_args$args; +} diff --git a/etc/php/php.dev.ini b/etc/php/php.dev.ini new file mode 100644 index 000000000..3a89b0e9e --- /dev/null +++ b/etc/php/php.dev.ini @@ -0,0 +1,66 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; PHP Development Environment Configuration ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +[PHP] +; Timezone setting +date.timezone = UTC + +; Error reporting settings - Development focused +display_errors = On +display_startup_errors = On +error_reporting = E_ALL +log_errors = On +error_log = /var/log/php/php_errors.log +report_memleaks = On +html_errors = On + +; Memory and execution limits for development +memory_limit = 256M +max_execution_time = 120 +max_input_time = 120 +post_max_size = 50M +upload_max_filesize = 50M + +; Development features +expose_php = On +assert.active = On +zend.assertions = 1 + +; Session settings +session.cache_limiter = nocache +session.use_strict_mode = 1 +session.cookie_httponly = 1 +session.cookie_secure = 1 +session.cookie_samesite = "Lax" +session.gc_maxlifetime = 7200 + +; Opcache settings for development +opcache.enable = 1 +opcache.memory_consumption = 128 +opcache.interned_strings_buffer = 8 +opcache.max_accelerated_files = 10000 +opcache.revalidate_freq = 0 +opcache.validate_timestamps = 1 +opcache.fast_shutdown = 1 +opcache.enable_cli = 1 + +; Xdebug 3 configuration +[Xdebug] +xdebug.mode = debug,develop,coverage +xdebug.start_with_request = yes +xdebug.client_host = host.docker.internal +xdebug.client_port = 9003 +xdebug.log = /tmp/xdebug.log +xdebug.log_level = 3 +xdebug.idekey = VSCODE +;xdebug.idekey = PHPSTORM + +; Development utilities +xdebug.cli_color = 1 +xdebug.var_display_max_depth = 8 +xdebug.var_display_max_children = 256 +xdebug.var_display_max_data = 1024 +xdebug.max_nesting_level = 256 +xdebug.show_error_trace = 1 +xdebug.file_link_format = vscode://file/%f:%l diff --git a/etc/php/php.ini b/etc/php/php.ini deleted file mode 100644 index 4f47c01f7..000000000 --- a/etc/php/php.ini +++ /dev/null @@ -1,29 +0,0 @@ -; PHP Configuration - -;[Date] -; Defines the default timezone used by the date functions -; http://php.net/date.timezone -;date.timezone = - -; Error handling -;display_errors = Off - -; Xdebug -; See https://xdebug.org/docs/all_settings - -;PHPStorm -[Xdebug] -xdebug.remote_enable=1 -xdebug.idekey=PHPSTORM -xdebug.profiler_enable=0 -xdebug.max_nesting_level=700 -xdebug.remote_host=192.168.0.1 # your ip -xdebug.remote_port=9000 - -;Netbeans -;[Xdebug] -;xdebug.remote_enable=1 -;xdebug.remote_handler=dbgp -;xdebug.remote_mode=req -;xdebug.remote_host=192.168.0.1 # your ip -;xdebug.remote_port=9000 \ No newline at end of file diff --git a/etc/php/php.prod.ini b/etc/php/php.prod.ini new file mode 100644 index 000000000..8e9b0a261 --- /dev/null +++ b/etc/php/php.prod.ini @@ -0,0 +1,72 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; PHP Production Environment Configuration ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +[PHP] +; Timezone setting +date.timezone = UTC + +; Error reporting settings - Production focused +display_errors = Off +display_startup_errors = Off +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT +log_errors = On +error_log = /var/log/php/php_errors.log +ignore_repeated_errors = On +report_memleaks = Off +html_errors = Off + +; Security settings +expose_php = Off +disable_functions = system,exec,shell_exec,passthru,proc_open,popen,show_source,phpinfo + +; Memory and execution limits - Optimized for production +memory_limit = 128M +max_execution_time = 60 +max_input_time = 60 +post_max_size = 20M +upload_max_filesize = 20M + +; Request handling +max_input_vars = 2000 +realpath_cache_size = 4M +realpath_cache_ttl = 600 + +; Session settings - Secure for production +session.use_strict_mode = 1 +session.cookie_httponly = 1 +session.cookie_secure = 1 +session.cookie_samesite = "Lax" +session.gc_maxlifetime = 3600 +session.use_only_cookies = 1 +session.gc_probability = 1 +session.gc_divisor = 100 + +; Performance optimizations +zlib.output_compression = On +zlib.output_compression_level = 4 +implicit_flush = Off + +; Opcache settings - Production optimized +opcache.enable = 1 +opcache.memory_consumption = 256 +opcache.interned_strings_buffer = 16 +opcache.max_accelerated_files = 20000 +opcache.revalidate_freq = 60 +opcache.validate_timestamps = 0 +opcache.fast_shutdown = 1 +opcache.enable_file_override = 1 +opcache.save_comments = 1 +opcache.enable_cli = 0 +opcache.huge_code_pages = 1 +opcache.jit = 1255 +opcache.jit_buffer_size = 128M + +; File handling +allow_url_fopen = Off +file_uploads = On +default_socket_timeout = 30 + +; Xdebug is disabled in production +[Xdebug] +xdebug.mode = off diff --git a/web/app/composer.json.dist b/web/app/composer.json.dist index b4850f712..9538a2042 100644 --- a/web/app/composer.json.dist +++ b/web/app/composer.json.dist @@ -1,22 +1,32 @@ { + "name": "nanoninja/docker-nginx-php-mysql", + "description": "Docker NGINX PHP MySQL development environment", + "type": "project", + "license": "MIT", "require": { - "symfony/yaml": "^5.1" + "php": ">=8.1", + "symfony/yaml": "^6.3" }, "require-dev": { - "phpmd/phpmd": "@stable", - "phpunit/phpunit": "^9.0", - "squizlabs/php_codesniffer": "3.5.*" + "phpmd/phpmd": "^2.13", + "phpunit/phpunit": "^10.0", + "squizlabs/php_codesniffer": "^3.7", + "phpstan/phpstan": "^1.10" }, "autoload": { "psr-4": { - "App\\Acme\\": "src/" + "App\\": "src/" } }, "autoload-dev": { "psr-4": { - "AppTest\\Acme\\": "test/" + "App\\Tests\\": "tests/" } }, + "config": { + "sort-packages": true, + "optimize-autoloader": true + }, "minimum-stability": "stable", "prefer-stable": true -} +} \ No newline at end of file diff --git a/web/app/phpunit.xml.dist b/web/app/phpunit.xml.dist index 7cd9c11cf..755f0c41f 100644 --- a/web/app/phpunit.xml.dist +++ b/web/app/phpunit.xml.dist @@ -1,27 +1,41 @@ - + - - ./test/ + + tests - - - ./src - - ./vendor - - - + + + src + + + vendor + + + + - - - - - + + + + + + + \ No newline at end of file diff --git a/web/app/public/index.php b/web/app/public/index.php new file mode 100644 index 000000000..dedb65fd9 --- /dev/null +++ b/web/app/public/index.php @@ -0,0 +1,310 @@ + + + + + + + + Welcome to Docker NGINX PHP MySQL + + + + + + + +
+

Docker NGINX PHP MySQL

+

Your modern PHP development environment

+ Ready +
+ +
+
+
+
+

Welcome to Your Docker Environment

+
+
+

Congratulations! If you're seeing this page, your PHP environment is running successfully.

+

This environment includes:

+
    +
  • NGINX web server
  • +
  • PHP
  • +
  • MySQL database
  • +
  • PHPMyAdmin (in development environment)
  • +
+

Current PHP class test: getName(); ?>

+
+
+ +

Key Features

+
+
+

Development & Production

+

Easily switch between development and production environments with optimized configurations.

+
+ make dev + make prod +
+
+ +
+

Framework Support

+

Ready-to-use support for popular PHP frameworks including Symfony and Laravel.

+
+ Symfony + Laravel +
+
+ +
+

Debugging Tools

+

Integrated with Xdebug and development tools to make debugging efficient and painless.

+
+ +
+

Security Features

+

Network separation with frontend and backend layers for enhanced security.

+
+
+ +

Developer Tools

+ + +
+
+ +
+
+

Docker NGINX PHP MySQL Environment ©

+
+
+ + + \ No newline at end of file diff --git a/web/app/src/Foo.php b/web/app/src/Foo.php index f982f487f..ed5ace1fa 100644 --- a/web/app/src/Foo.php +++ b/web/app/src/Foo.php @@ -1,14 +1,9 @@ assertEquals($foo->getName(), 'Nginx PHP MySQL'); + $this->assertEquals($foo->getName(), 'Docker Nginx PHP MySQL'); } } diff --git a/web/app/tests/bootstrap.php b/web/app/tests/bootstrap.php new file mode 100644 index 000000000..112d59201 --- /dev/null +++ b/web/app/tests/bootstrap.php @@ -0,0 +1,16 @@ + - - - - Docker <?php echo $foo->getName(); ?> - - -

Docker getName(); ?>

- -