Tuesday, October 8, 2024

Use nginx running in Docker container to serve php sites running on the host

In one of my previous articles I showed how to use nginx running in Docker container to serve .Net sites running on Kestrel web server on the host. In the current article I will show how to do similar thing with php sites.

So idea is the same: we have nginx running in Docker container and number of php sites running on the host and want containerized nginx to serve these sites. For example we will use Mantis (popular bug tracker) and Wordpress (popular CMS engine based on php) sites. For simplicity we will use assumption that MySQL databases used by php sites are running on the same host.

On the host php sites are served by php fpm daemon (php FastCGI process manager) which may listen for IP:port or unix sockets. One option is to use this php fpm from the host, however e.g. in case of unix sockets it will require tricky rights setups. Also since we anyway eager to move to containers it will be preferable to create lightweight php fpm container which will serve our php sites from the host. First of all we need to create Docker image based on php fpm with MySQL extension installed (so php will be able to connect to MySQL db). It can be created with the following Dockerilfe:

FROM php:7.4-fpm
RUN docker-php-ext-install mysqli pdo_mysql

On the first line we tell Docker that our image should be based on php fpm v7.4 and on the 2nd line we install MySQL extension for php so it will be able to connect to the database. Note that by default php fpm containers listen port 9000 - it will be used when we will configure nginx.conf file for our site.

Then build the image and push it to our Docker images registry:

docker build -t {php-image-tag}
docker push {php-image-tag}

On the next step we need to setup nginx and php containers with the following docker compose file:

name: myservice
services:
  nginx:
    image: nginx:latest
volumes:
- /var/www/myphpsite:/var/www/myphpsite ports: - 80:80 restart: always networks: - mynetwork extra_hosts: - host.docker.internal:host-gateway
php:
image: {php-image-tag}
volumes:
- /var/www/myphpsite:/var/www/myphpsite
restart: unless-stopped
networks:
- mynetwork
extra_hosts:
- host.docker.internal:host-gateway

Important line here is where we add a volume which points to the folder with php scripts (/var/www/myphpsite) both to nginx and php. With this line nginx container will be able to serve also static files (css, images, js, etc) from our php site and at the same time php container will have access to php scripts. Also it is important that nginx and php containers are located in the same network (mynetwork) (in this case containers will be able to communicate using containers names) and that we added host.docker.internal extra host (so php fpm container will be able to connect to the database running on the host).

Next step is to setup nginx.conf for our php site:

server {
    listen 80;
    server_name example.com;
    root /var/www/myphpsite;
    ...
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass myservice-php-1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }
}

Here with root directive we specify that php sources are located in /var/www/myphpsite folder (remember that we added this folder to php and nginx containers volumes) and configure php fpm to process php scripts. Directive fastcgi_pass instructs nginx to execute a CGI script (php in our case) using the FastCGI protocol (which is different from proxy_pass directive used for .Net sites running on Kestrel - which sends an HTTP request to another web server). Since both containers are located in the same network we may use container name (myservice-php-1) and port number (9000) for fastcgi_pass directive.

And last but not least - since php scripts will be processed inside container we need to change host in database connection string from localhost to host.docker.internal (we can do that because added extra_host to our containers in docker compose files). Location where it is stored depends on php site. E.g. for Mantis it is stored in /.../{site_folder}/config/config_inc.php in $g_hostname variable, for Wordpress-based sites in /var/www/{site_folder}/wp-config.php in DB_HOST variable. After that your php sites will work under nginx running in Docker container.

No comments:

Post a Comment