DEV Community

Daniil Bazhenov
Daniil Bazhenov

Posted on • Edited on

How to Develop a Simple Web Application Using Docker-compose, Nginx, PHP 8, and MongoDB 6

I will give you a brief introduction to setting up an environment for developing a PHP application using MongoDB.

I use the environment for local development and release the application on the server if the application is not business-critical.

For example, one application reads and processes AWS price lists (in JSON format), stores them in a database, and uses the data to process, report, and publish them to the Web site for review.

The environment uses

  • Docker-compose
  • Nginx web server
  • PHP 8.2 (PHP-FPM) + Composer
  • MongoDB 6

Preparing Docker image with PHP + Composer + packages for MongoDB

You need to create a Dockerfile in the project directory

Dockerfile



FROM php:8.2-fpm

RUN apt-get -y update \
    && apt-get install -y libssl-dev pkg-config libzip-dev unzip git

RUN pecl install zlib zip mongodb \
    && docker-php-ext-enable zip \
    && docker-php-ext-enable mongodb

# Install composer (updated via entry point)
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer


Enter fullscreen mode Exit fullscreen mode

Run Image build from Dockerfile



docker build -t php8.2-fpm-mongo .


Enter fullscreen mode Exit fullscreen mode

After completing the build, this Image can be used in the docker-compose.yml file, there will already be Composer and the libraries needed to run MongoDB.

Preparing Docker-compose with Nginx + PHP

You need to create a docker-compose.yml file in the application directory.

docker-compose.yml



version: '3.9'

services:
  web:
    image: nginx:latest
    ports:
      - '80:80'
    volumes:
      - ./app:/var/www/html
      - ./config/default.conf:/etc/nginx/conf.d/default.conf

  php-fpm:
    image: php8.2-fpm-mongo
    volumes:
      - ./app:/var/www/html


Enter fullscreen mode Exit fullscreen mode

You also need to create a directory app/ and an index.php file in it, which will be our application.

app/index.php



<?php

phpinfo();

exit;


Enter fullscreen mode Exit fullscreen mode

You will also need to create a Nginx default.conf configuration file. I placed it in the config/ folder in the project directory

config/default.conf



server {
    listen 80;
    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;

    rewrite ^/(.*)/$ /$1 permanent; 

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_buffering off;
    }
}


Enter fullscreen mode Exit fullscreen mode

Structure of files and folders



.
├── app
│    └── index.php
├── config
│    └── default.conf
├── Dockerfile
└── docker-compose.yml


Enter fullscreen mode Exit fullscreen mode

Checking Nginx + PHP

Run docker-compose



docker-compose up -d


Enter fullscreen mode Exit fullscreen mode

Open localhost in the browser.

If everything is correct, you should see phpinfo.

Installing PHP libraries into the project with Composer required by MongoDB

You need to create a composer.json file in the app folder to install the packages and php extensions that are required for MongoDB.

app/composer.json



{
    "require": {
        "mongodb/mongodb": "^1.6",
        "ext-mongodb": "^1.6"
    }
}


Enter fullscreen mode Exit fullscreen mode

To install packages you need to connect to the container with php-fpm:



docker exec -it [php-fpm-container] bash


Enter fullscreen mode Exit fullscreen mode

The container name becomes known when you run docker-compose up -d

Once you are connected to the container, install composer packages with the command:



composer install


Enter fullscreen mode Exit fullscreen mode

I think all went well and your project now has a vendor directory with installed packages and libraries for MongoDB

Adding MongoDB image to Docker-compose

You need to add the mongodb service to the previously created docker-compose.yml

Stop launched containers with the command



docker-compose down


Enter fullscreen mode Exit fullscreen mode

Add a new service to docker-compose.yml



  mongodb:
    image: "percona/percona-server-mongodb:6.0.4"
    # image: "percona/percona-server-mongodb:6.0.4-3-arm64" # For Apple M1/M2
    volumes:
      - ./data:/data/db
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: secret
      MONGO_INITDB_DATABASE: tutorial
    ports: 
      - "27017:27017"


Enter fullscreen mode Exit fullscreen mode

I use Percona Server for MongoDB as a free open-source alternative to MongoDB.

You will also need to modify the php-fpm service a bit to include environment variables



  php-fpm:
    image: php8.2-fpm-mongo
    volumes:
      - ./app:/var/www/html
    environment:
      DB_USERNAME: root
      DB_PASSWORD: secret
      DB_HOST: mongodb # matches the service with mongodb


Enter fullscreen mode Exit fullscreen mode

This way the final docker-compose.yml will be



version: '3.9'

services:
  web:
    image: nginx:latest
    ports:
      - '80:80'
    volumes:
      - ./app:/var/www/html
      - ./config/default.conf:/etc/nginx/conf.d/default.conf

  php-fpm:
    image: php8.2-fpm-mongo
    volumes:
      - ./app:/var/www/html
    environment:
      DB_USERNAME: root
      DB_PASSWORD: secret
      DB_HOST: mongodb # matches the service with mongodb

  mongodb:
    image: "percona/percona-server-mongodb:6.0.4"
    # image: "percona/percona-server-mongodb:6.0.4-3-arm64" # For Apple Silicon M1/M2
    volumes:
      - ./data:/data/db
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: secret
      MONGO_INITDB_DATABASE: tutorial
    ports: 
      - "27017:27017"


Enter fullscreen mode Exit fullscreen mode

Run docker-compose



docker-compose up -d


Enter fullscreen mode Exit fullscreen mode

Let's connect to MongoDB in a PHP application and write the test data

You need to modify the app/index.php file



<?php

// Enabling Composer Packages
require __DIR__ . '/vendor/autoload.php';

// Get environment variables
$local_conf = getenv();
define('DB_USERNAME', $local_conf['DB_USERNAME']);
define('DB_PASSWORD', $local_conf['DB_PASSWORD']);
define('DB_HOST', $local_conf['DB_HOST']);

// Connect to MongoDB
$db_client = new \MongoDB\Client('mongodb://'. DB_USERNAME .':' . DB_PASSWORD . '@'. DB_HOST . ':27017/');

$db = $db_client->selectDatabase('tutorial');

// Create an index
$db->pages->createIndex(['page_id' => 1]);

// Test insert data
for ($page = 1; $page <= 1000; $page++) {

    $data = [
        'page_id' => $page, 
        'title' => "Page " . $page,
        'date' => date("m.d.y H:i:s"),
        'timestamp' => time(),
        'mongodb_time' => new MongoDB\BSON\UTCDateTime(time() * 1000)
    ];

    $updateResult = $db->pages->updateOne(
        [
            'page_id' => $page // query 
        ],
        ['$set' => $data],
        ['upsert' => true]
    );

    echo $page . " " ;
}
echo '<br/>Finish';
exit;


Enter fullscreen mode Exit fullscreen mode

This is a simple script that:

  1. Reads environment variables
  2. Connects to the database
  3. Creates Index by key
  4. Writes 1000 test documents in a loop.

You can run localhost in your browser.

Checking database records with MongoDB Compass

Install MongoDB Compass, it's a great tool to check the results of your experiments.

Use localhost as host and user/pass from docker-compose.yml
Image description

Conclusion

The environment and an example of a minimal application are ready. It can be expanded and improved by adding logic and functions.

Suggestions and comments are welcome.

The project files and example code are available in the Github repository

In the next part, you will learn how to improve the script to make HTTP requests to the API using the GitHub API as an example. Link to next part

Top comments (2)

Collapse
 
void1995 profile image
void

i receive this error in the end on my localhost

Fatal error: Uncaught MongoDB\Driver\Exception\ConnectionTimeoutException: No suitable servers found (serverSelectionTryOnce set): [Failed to resolve 'mongodb'] in /var/www/html/vendor/mongodb/mongodb/src/functions.php:565 Stack trace: #0 /var/www/html/vendor/mongodb/mongodb/src/functions.php(565): MongoDB\Driver\Manager->selectServer(Object(MongoDB\Driver\ReadPreference)) #1 /var/www/html/vendor/mongodb/mongodb/src/Collection.php(382): MongoDB\select_server(Object(MongoDB\Driver\Manager), Array) #2 /var/www/html/vendor/mongodb/mongodb/src/Collection.php(350): MongoDB\Collection->createIndexes(Array, Array) #3 /var/www/html/index.php(18): MongoDB\Collection->createIndex(Array) #4 {main} thrown in /var/www/html/vendor/mongodb/mongodb/src/functions.php on line 565

Collapse
 
dbazhenov profile image
Daniil Bazhenov

That's weird,

  1. did MongoDB run in Docker without errors? Do you see it as green in Docker Desktop?
  2. Try installing MongoDB Atlas and connect to MongoDB, use the same connection parameters in the PHP script.