 {"id":516897,"date":"2024-08-24T13:14:22","date_gmt":"2024-08-24T20:14:22","guid":{"rendered":"https:\/\/jorgep.com\/blog\/?p=516897"},"modified":"2025-03-09T21:04:44","modified_gmt":"2025-03-10T04:04:44","slug":"setting-up-a-php-development-environment-on-windows-using-docker","status":"publish","type":"post","link":"https:\/\/jorgep.com\/blog\/setting-up-a-php-development-environment-on-windows-using-docker\/","title":{"rendered":"Setting Up a PHP Development Environment on Windows Using Docker"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\">Introduction<\/h3>\n\n\n\n<p>Setting up a PHP development environment can be a daunting task, especially when you want to ensure consistency across different setups. Docker simplifies this process by providing a containerized environment that can be easily replicated. In this guide, we&#8217;ll walk you through the steps to set up a PHP development environment on Windows using Docker, including Apache, MySQL, and phpMyAdmin.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>You can set up a robust PHP development environment on Windows using Docker. This setup ensures consistency and makes it easy to manage your development environment.  <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<p>Before we begin, make sure you have the following installed on your Windows machine:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Docker Desktop<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Install Docker<\/h3>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Download Docker Desktop<\/strong>: Go to the Docker website and download Docker Desktop for Windows.<\/li>\n\n\n\n<li><strong>Install Docker Desktop<\/strong>: Follow the installation instructions. Make sure to enable the required Windows features ( WSL 2) during the installation process.<\/li>\n\n\n\n<li><strong>Start Docker Desktop<\/strong>: Once installed, start Docker Desktop and ensure it\u2019s running.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Create a Dockerfile<\/h3>\n\n\n\n<p>Create a <code>Dockerfile<\/code> in your project directory. This file will define the PHP environment.<\/p>\n\n\n\n<p>dockerfile<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Use the official PHP 8.2 image\nFROM php:8.2-apache\n\n# Install necessary PHP extensions\nRUN docker-php-ext-install pdo pdo_mysql\n\n# Enable Apache mod_rewrite\nRUN a2enmod rewrite\n\n# Copy project files to the container\nCOPY . \/var\/www\/html\n\n# Set working directory\nWORKDIR \/var\/www\/html\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Create a Docker Compose File<\/h3>\n\n\n\n<p>Create a <code>docker-compose.yml<\/code> file in your project directory. This file will define the services (like PHP, MySQL, and phpMyAdmin) that your application needs.<\/p>\n\n\n\n<p>yaml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>version: '3.8'\n\nservices:\n  web:\n    build: .\n    ports:\n      - \"7080:80\"\n    volumes:\n      - .:\/var\/www\/html\n    depends_on:\n      - db\n    networks:\n      - mynetwork\n\n  db:\n    image: mysql:5.7\n    environment:\n      MYSQL_ROOT_PASSWORD: root\n      MYSQL_DATABASE: mydatabase\n      MYSQL_USER: user\n      MYSQL_PASSWORD: password\n    volumes:\n      - db_data:\/var\/lib\/mysql\n    networks:\n      - mynetwork\n\n  phpmyadmin:\n    image: phpmyadmin\/phpmyadmin\n    restart: always\n    ports:\n      - \"8080:80\"\n    environment:\n      PMA_HOST: db\n      MYSQL_ROOT_PASSWORD: root\n    networks:\n      - mynetwork\n\nnetworks:\n  mynetwork:\n    driver: bridge\n\nvolumes:\n  db_data:\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Build and Run the Docker Containers<\/h3>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Open a terminal<\/strong>: PowerShell or cmd terminal ok!. <br>Navigate to your project directory.  <\/li>\n\n\n\n<li><strong>Build the Docker image<\/strong>: Run the following command to build the Docker image:<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>d<span style=\"background-color: initial; font-family: inherit; font-size: 0.8rem; color: var(--global-palette4);\">ocker-compose build<\/span><\/code><\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Start the Docker containers<\/strong>: Run the following command to start the containers:<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code>docker-compose up<\/code><\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Access Your PHP Application<\/h3>\n\n\n\n<p>Open your web browser and go to <code>http:\/\/localhost:7080<\/code>. You should see your PHP application running with PHP 8.2.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Access phpMyAdmin<\/h3>\n\n\n\n<p>Open your web browser and go to <code>http:\/\/localhost:8080<\/code>. You should see the phpMyAdmin login page. Use the following credentials to log in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Server<\/strong>: <code>db<\/code><\/li>\n\n\n\n<li><strong>Username<\/strong>: <code>root<\/code><\/li>\n\n\n\n<li><strong>Password<\/strong>: <code>root<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 7: Place Your Code<\/h3>\n\n\n\n<p>can you expand a little of where the \/var\/www\/html is in my local machine?<\/p>\n\n\n\n<p>Certainly! Let&#8217;s clarify how the <code>\/var\/www\/html<\/code> directory in the Docker container relates to your local machine.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Understanding <code>\/var\/www\/html<\/code> in Docker<\/h3>\n\n\n\n<p>When you use Docker, the <code>\/var\/www\/html<\/code> directory is inside the Docker container. This directory is the default document root for the Apache web server in the container. However, this directory doesn&#8217;t exist on your local machine in the same way. Instead, Docker maps a directory from your local machine to this directory inside the container.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Mapping Local Directory to Container Directory<\/h3>\n\n\n\n<p>In your <code>docker-compose.yml<\/code> file, you have a volume mapping that looks like this:<\/p>\n\n\n\n<p>yaml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  web:\n    build: .\n    ports:\n      - \"7080:80\"\n    volumes:\n      - .:\/var\/www\/html\n<\/code><\/pre>\n\n\n\n<p>This line:<\/p>\n\n\n\n<p>yaml<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>- .:\/var\/www\/html\n<\/code><\/pre>\n\n\n\n<p>means that the current directory on your local machine (denoted by <code>.<\/code>) is mapped to the <code>\/var\/www\/html<\/code> directory inside the Docker container.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Example Directory Structure<\/h3>\n\n\n\n<p>Here&#8217;s an example of how your project directory might look on your local machine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>C:\\Users\\YourUsername\\YourProject\n|-- Dockerfile\n|-- docker-compose.yml\n|-- index.php\n|-- other-files-and-directories\n<\/code><\/pre>\n\n\n\n<p>Keep in mind that c:\\Users\\YourUsername\\YourProject is just an example  that depends on where you  created the docker image  in my case i started all of this at:   c:\\LocalData\\DevEnv<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Place your PHP code in the root directory of your project, where your <code>Dockerfile<\/code> and <code>docker-compose.yml<\/code> are located. This directory will be mapped to the container&#8217;s <code>\/var\/www\/html<\/code> directory.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>You should place your PHP code and other project files in the same directory where your <code>Dockerfile<\/code> and <code>docker-compose.yml<\/code> are located. For example, if your project directory on Windows is <code>C:\\Users\\YourUsername\\YourProject<\/code>, you should place your PHP files and other project files in this directory.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Where to Place Your Code<\/h3>\n\n\n\n<p>You should place your PHP code and other project files in the same directory where your <code>Dockerfile<\/code> and <code>docker-compose.yml<\/code> are located. For example, if your project directory on Windows is <code>C:\\Users\\YourUsername\\YourProject<\/code>, you should place your PHP files and other project files in this directory.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Create an index.html that has &lt;h1&gt;Hello You are Here!&lt;\/&gt; inside the at the YourProject directory and go to <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PHP Application: http:\/\/localhost:7080\n\nphpMyAdmin: http:\/\/localhost:8080<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"510\" src=\"https:\/\/jorgep.com\/blog\/wp-content\/uploads\/image-116-1024x510.png\" alt=\"\" class=\"wp-image-516902\" srcset=\"https:\/\/jorgep.com\/blog\/wp-content\/uploads\/image-116-1024x510.png 1024w, https:\/\/jorgep.com\/blog\/wp-content\/uploads\/image-116-300x149.png 300w, https:\/\/jorgep.com\/blog\/wp-content\/uploads\/image-116-768x382.png 768w, https:\/\/jorgep.com\/blog\/wp-content\/uploads\/image-116.png 1256w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">UPDATING THE Docker Container: <\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>So if you need to change or update the docker contain you can delete and rebuild from scratch after you update files:   dockerfile and docker-compose.yml <\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker-compose down\ndocker-compose build\ndocker-compose up\n<\/code><\/pre>\n\n\n\n<p>Alternatively:   You can YOUDATE the running container without rebuilding it from scratch!<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Update Your Dockerfile or docker-compose.yml<\/strong>: Make any necessary changes to your Dockerfile or docker-compose.yml file.<\/li>\n\n\n\n<li><strong>Run the Update Command<\/strong>: Use the following command to update your running containers:<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>docker-compose up --build<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>This command will rebuild the services that have changed and restart the containers, applying the updates without needing to stop and remove the existing containers manually.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Adding WordPress to your development Environment<\/h2>\n\n\n\n<p>I decided that at this time, want to keep WordPress outside my docker container ( do not have any good reasons other than the fact that I may need to delete \/change\/ update the core at any time.      What I did next: <\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Download zip file with latest copy WordPress  from wordpress.org<\/li>\n\n\n\n<li>create a directory called wordpress off the YourProject directory <\/li>\n\n\n\n<li>the extract zip file to the &#8230;\\YourProject\\wordpress   <\/li>\n\n\n\n<li>go to <a href=\"http:\/\/localhost:7080\/wordpress\">http:\/\/localhost:7080\/wordpress<\/a><\/li>\n\n\n\n<li>and initiate the wordpress setup  \n<ul class=\"wp-block-list\">\n<li>Note 1:  when asked for the Database credentials, use whatever you used in the YML file above.  In my case it was: <\/li>\n\n\n\n<li> MYSQL Parameters:<\/li>\n\n\n\n<li><strong>Host<\/strong>: <code>db<\/code> <\/li>\n\n\n\n<li><strong>Port<\/strong>: <code>3306<\/code> (default MySQL port so no need to enter)<\/li>\n\n\n\n<li><strong>Database Name<\/strong>: <code>mydatabase<\/code><\/li>\n\n\n\n<li><strong>User<\/strong>: <code>user<\/code><\/li>\n\n\n\n<li><strong>Password<\/strong>: <code>password<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Then I tried to install a plugins, and it asked me for FTP credentials, so I had to add the following line to the wp-config.php file:  \n<ul class=\"wp-block-list\">\n<li>define(&#8216;FS_METHOD&#8217;, &#8216;direct&#8217;);<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Setting up a PHP development environment can be a daunting task, especially when you want to ensure consistency across different setups. Docker simplifies this process by providing a containerized environment that can be easily replicated. In this guide, we&#8217;ll walk you through the steps to set up a PHP development environment on Windows using&#8230;<\/p>\n","protected":false},"author":2,"featured_media":516904,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","ngg_post_thumbnail":0,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"categories":[441],"tags":[942,569],"class_list":["post-516897","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech-talk","tag-home-lab","tag-wordpress"],"taxonomy_info":{"category":[{"value":441,"label":"Tech Talk"}],"post_tag":[{"value":942,"label":"home lab"},{"value":569,"label":"WordPress"}]},"featured_image_src_large":["https:\/\/jorgep.com\/blog\/wp-content\/uploads\/DockerPHP-Dev-Phpblogpost800x300.jpg",800,300,false],"author_info":{"display_name":"Jorge Pereira","author_link":"https:\/\/jorgep.com\/blog\/author\/jorge\/"},"comment_info":0,"category_info":[{"term_id":441,"name":"Tech Talk","slug":"tech-talk","term_group":0,"term_taxonomy_id":451,"taxonomy":"category","description":"","parent":0,"count":686,"filter":"raw","cat_ID":441,"category_count":686,"category_description":"","cat_name":"Tech Talk","category_nicename":"tech-talk","category_parent":0}],"tag_info":[{"term_id":942,"name":"home lab","slug":"home-lab","term_group":0,"term_taxonomy_id":952,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":569,"name":"WordPress","slug":"wordpress","term_group":0,"term_taxonomy_id":579,"taxonomy":"post_tag","description":"","parent":0,"count":48,"filter":"raw"}],"_links":{"self":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts\/516897","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/comments?post=516897"}],"version-history":[{"count":0,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/posts\/516897\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/media\/516904"}],"wp:attachment":[{"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/media?parent=516897"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/categories?post=516897"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgep.com\/blog\/wp-json\/wp\/v2\/tags?post=516897"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}