Tools: Creating a simple environment with Docker, PHP 8.4, Composer, Nginx, and MariaDB.

Tools: Creating a simple environment with Docker, PHP 8.4, Composer, Nginx, and MariaDB.

Source: Dev.to

Project structure ## PHP 8.4 with Composer (Dockerfile) ## What this Dockerfile does ## Simple Nginx configuration ## What this configuration does ## Docker Compose (the core of the setup) ## What this docker-compose.yml does ## version ## php service ## nginx service ## mariadb service ## Volumes ## Services overview ## PHP test file (with database connection) ## What this test file does ## Composer configuration ## Running the environment ## Conclusion This is my first article on this platform, and the goal here is to keep things simple, practical, and easy to follow. You've probably had trouble installing PHP extensions, configuring Nginx, or installing a database on your local machine, just like me; Docker can make your life much easier. In this guide, we will build a modern and simple development environment using: All services will run together with a single command. Start by creating the following folder structure: Each folder has a clear responsibility: Create the file docker/php/Dockerfile: Create the file docker/nginx/default.conf: This setup is minimal but works well for APIs and simple PHP applications. Create the file docker-compose.yml in the project root: This file defines and connects all services needed for the development environment. Defines the Docker Compose file format version. Version 3.9 is stable and widely supported. This named volume persists database data even if containers are stopped or recreated. The mariadb_data volume ensures that database data is not lost when containers stop. Create the file src/index.php: If you see the success message in the browser, it means PHP, Nginx, and MariaDB are communicating correctly. Create the file composer.json: To run Composer inside the PHP container: This command uses the same PHP environment defined in Docker, avoiding local PHP version issues. From the project root, run: Then open your browser: http://localhost:8080 If everything is working, you should see: With this setup you get: This is a solid starting point for plain PHP projects and APIs. That's all for today, folks! Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: root-folder/ ├── docker/ │ ├── nginx/ │ │ └── default.conf │ └── php/ │ └── Dockerfile ├── src/ │ └── index.php ├── docker-compose.yml └── composer.json Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: root-folder/ ├── docker/ │ ├── nginx/ │ │ └── default.conf │ └── php/ │ └── Dockerfile ├── src/ │ └── index.php ├── docker-compose.yml └── composer.json CODE_BLOCK: root-folder/ ├── docker/ │ ├── nginx/ │ │ └── default.conf │ └── php/ │ └── Dockerfile ├── src/ │ └── index.php ├── docker-compose.yml └── composer.json COMMAND_BLOCK: # Base image with PHP 8.4 and FPM FROM php:8.4-fpm # Install system dependencies and PHP extensions RUN apt-get update && apt-get install -y \ git \ unzip \ libzip-dev \ && docker-php-ext-install pdo pdo_mysql zip # Install Composer from the official image COPY --from=composer:2 /usr/bin/composer /usr/bin/composer # Set the working directory WORKDIR /var/www/html Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # Base image with PHP 8.4 and FPM FROM php:8.4-fpm # Install system dependencies and PHP extensions RUN apt-get update && apt-get install -y \ git \ unzip \ libzip-dev \ && docker-php-ext-install pdo pdo_mysql zip # Install Composer from the official image COPY --from=composer:2 /usr/bin/composer /usr/bin/composer # Set the working directory WORKDIR /var/www/html COMMAND_BLOCK: # Base image with PHP 8.4 and FPM FROM php:8.4-fpm # Install system dependencies and PHP extensions RUN apt-get update && apt-get install -y \ git \ unzip \ libzip-dev \ && docker-php-ext-install pdo pdo_mysql zip # Install Composer from the official image COPY --from=composer:2 /usr/bin/composer /usr/bin/composer # Set the working directory WORKDIR /var/www/html COMMAND_BLOCK: server { listen 80; index index.php index.html; root /var/www/html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: server { listen 80; index index.php index.html; root /var/www/html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } COMMAND_BLOCK: server { listen 80; index index.php index.html; root /var/www/html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } CODE_BLOCK: version: '3.9' services: php: build: ./docker/php container_name: php84 volumes: - ./src:/var/www/html depends_on: - mariadb nginx: image: nginx:latest container_name: nginx ports: - "8080:80" volumes: - ./src:/var/www/html - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php mariadb: image: mariadb:11 container_name: mariadb environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: app MYSQL_USER: app MYSQL_PASSWORD: app ports: - "3306:3306" volumes: - mariadb_data:/var/lib/mysql volumes: mariadb_data: Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: version: '3.9' services: php: build: ./docker/php container_name: php84 volumes: - ./src:/var/www/html depends_on: - mariadb nginx: image: nginx:latest container_name: nginx ports: - "8080:80" volumes: - ./src:/var/www/html - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php mariadb: image: mariadb:11 container_name: mariadb environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: app MYSQL_USER: app MYSQL_PASSWORD: app ports: - "3306:3306" volumes: - mariadb_data:/var/lib/mysql volumes: mariadb_data: CODE_BLOCK: version: '3.9' services: php: build: ./docker/php container_name: php84 volumes: - ./src:/var/www/html depends_on: - mariadb nginx: image: nginx:latest container_name: nginx ports: - "8080:80" volumes: - ./src:/var/www/html - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php mariadb: image: mariadb:11 container_name: mariadb environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: app MYSQL_USER: app MYSQL_PASSWORD: app ports: - "3306:3306" volumes: - mariadb_data:/var/lib/mysql volumes: mariadb_data: CODE_BLOCK: version: '3.9' Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: version: '3.9' CODE_BLOCK: version: '3.9' CODE_BLOCK: php: build: ./docker/php container_name: php84 volumes: - ./src:/var/www/html depends_on: - mariadb Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: php: build: ./docker/php container_name: php84 volumes: - ./src:/var/www/html depends_on: - mariadb CODE_BLOCK: php: build: ./docker/php container_name: php84 volumes: - ./src:/var/www/html depends_on: - mariadb CODE_BLOCK: nginx: image: nginx:latest container_name: nginx ports: - "8080:80" volumes: - ./src:/var/www/html - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: nginx: image: nginx:latest container_name: nginx ports: - "8080:80" volumes: - ./src:/var/www/html - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php CODE_BLOCK: nginx: image: nginx:latest container_name: nginx ports: - "8080:80" volumes: - ./src:/var/www/html - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php CODE_BLOCK: mariadb: image: mariadb:11 container_name: mariadb environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: app MYSQL_USER: app MYSQL_PASSWORD: app ports: - "3306:3306" volumes: - mariadb_data:/var/lib/mysql Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: mariadb: image: mariadb:11 container_name: mariadb environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: app MYSQL_USER: app MYSQL_PASSWORD: app ports: - "3306:3306" volumes: - mariadb_data:/var/lib/mysql CODE_BLOCK: mariadb: image: mariadb:11 container_name: mariadb environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: app MYSQL_USER: app MYSQL_PASSWORD: app ports: - "3306:3306" volumes: - mariadb_data:/var/lib/mysql CODE_BLOCK: volumes: mariadb_data: Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: volumes: mariadb_data: CODE_BLOCK: volumes: mariadb_data: COMMAND_BLOCK: <?php $host = 'mariadb'; $db = 'app'; $user = 'app'; $pass = 'app'; $charset = 'utf8mb4'; $port = 3306; $dsn = "mysql:host={$host};port={$port};dbname={$db};charset={$charset}"; try { $pdo = new PDO( $dsn, $user, $pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); echo "PHP is running and connected to MariaDB successfully!"; } catch (PDOException $e) { echo "Database connection failed: {$e->getMessage()}"; } Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: <?php $host = 'mariadb'; $db = 'app'; $user = 'app'; $pass = 'app'; $charset = 'utf8mb4'; $port = 3306; $dsn = "mysql:host={$host};port={$port};dbname={$db};charset={$charset}"; try { $pdo = new PDO( $dsn, $user, $pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); echo "PHP is running and connected to MariaDB successfully!"; } catch (PDOException $e) { echo "Database connection failed: {$e->getMessage()}"; } COMMAND_BLOCK: <?php $host = 'mariadb'; $db = 'app'; $user = 'app'; $pass = 'app'; $charset = 'utf8mb4'; $port = 3306; $dsn = "mysql:host={$host};port={$port};dbname={$db};charset={$charset}"; try { $pdo = new PDO( $dsn, $user, $pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); echo "PHP is running and connected to MariaDB successfully!"; } catch (PDOException $e) { echo "Database connection failed: {$e->getMessage()}"; } CODE_BLOCK: { "name": "example/docker-php", "require": {} } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: { "name": "example/docker-php", "require": {} } CODE_BLOCK: { "name": "example/docker-php", "require": {} } COMMAND_BLOCK: docker compose run --rm php composer install Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: docker compose run --rm php composer install COMMAND_BLOCK: docker compose run --rm php composer install COMMAND_BLOCK: docker compose up -d --build Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: docker compose up -d --build COMMAND_BLOCK: docker compose up -d --build CODE_BLOCK: PHP is running and connected to MariaDB successfully! Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: PHP is running and connected to MariaDB successfully! CODE_BLOCK: PHP is running and connected to MariaDB successfully! - PHP 8.4 (FPM) - Docker and Docker Compose - docker/php: PHP image and extensions - docker/nginx: Nginx configuration - src: application source code - Uses PHP 8.4 FPM, ideal for Nginx - Installs common system tools (git, unzip) - Enables essential PHP extensions for database and zip handling - Adds Composer without manual installation - Listens on port 80 - Serves files from /var/www/html - Forwards .php requests to the PHP container via FastCGI - Builds a custom PHP image using the Dockerfile inside docker/php - Mounts the local src folder into the container so changes are reflected instantly - Depends on MariaDB, ensuring the database container starts first - Uses the official Nginx image - Maps port 8080 on your machine to port 80 inside the container - Shares the same application code with PHP - Loads the custom Nginx configuration file - Depends on the PHP container to handle .php requests - Runs MariaDB version 11 - Automatically creates a database and user on startup - Exposes port 3306 for local connections (optional for development) - Stores database data in a named volume - php: runs PHP 8.4 with Composer - nginx: handles HTTP requests - mariadb: provides a persistent database - Uses PDO, the recommended way to connect to databases in PHP - Connects to MariaDB using the service name mariadb as the host - Reuses the same credentials defined in docker-compose.yml - Prints a success message if the connection works - Displays an error message if something goes wrong - PHP 8.4 ready for development - Composer fully integrated - Nginx as a lightweight web server - MariaDB with persistent data - A clean and isolated development environment