Sturm
Sturm

Reputation: 759

How do I get PHP-FPM to work with nginx-proxy with FastCGI?

I am attempting to get nginx-proxy to work with the php-fpm variant of the official php image via fastcgi. Unfortunately, I seem to be unable to do so. I'm sure the problem is just something simple that I don't know about.

I have followed the instructions for nginx-proxy to the best of my ability and have boiled it down to a very simple way to re-create the issue. Here's my docker-compose.yml file:

version: "3"

services:
  proxy:
    image: jwilder/nginx-proxy
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
    environment:
      - DEFAULT_HOST=test.local

  fpm:
    image: php:fpm
    environment:
      - VIRTUAL_HOST=test.local
      - VIRTUAL_PROTO=fastcgi

I then drop in a simple index.php file by running:

docker container exec -it web_fpm_1 /bin/bash -c 'echo "<?php phpinfo(); ?>" > /var/www/html/index.php'

(It puts web_ in front because this project is in a directory named web/.)

I also modify my hosts file to point test.local to 127.0.0.1, so I can test it. However, every attempt to browse to test.local results in a blank white page.

The logs for the web_proxy_1 container don't indicate anything out of the ordinary, as far as I know:

❯ docker container logs web_proxy_1
WARNING: /etc/nginx/dhparam/dhparam.pem was not found. A pre-generated dhparam.pem will be used for now while a new one
is being generated in the background.  Once the new dhparam.pem is in place, nginx will be reloaded.
forego     | starting dockergen.1 on port 5000
forego     | starting nginx.1 on port 5100
dockergen.1 | 2020/07/20 19:24:54 Generated '/etc/nginx/conf.d/default.conf' from 2 containers
dockergen.1 | 2020/07/20 19:24:54 Watching docker events
dockergen.1 | 2020/07/20 19:24:54 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload'
nginx.1    | test.local 172.18.0.1 - - [20/Jul/2020:19:25:12 +0000] "GET / HTTP/1.1" 200 5 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
nginx.1    | test.local 172.18.0.1 - - [20/Jul/2020:19:25:13 +0000] "GET /favicon.ico HTTP/1.1" 200 5 "http://test.local/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"

The logs for the web_fpm_1 container show that nothing gets sent except a 200 response:

❯ docker container logs web_fpm_1
[20-Jul-2020 19:24:54] NOTICE: fpm is running, pid 1
[20-Jul-2020 19:24:54] NOTICE: ready to handle connections
172.18.0.3 -  20/Jul/2020:19:25:12 +0000 "- " 200
172.18.0.3 -  20/Jul/2020:19:25:13 +0000 "- " 200

What am I doing wrong?

Incidentally, I have asked this question on the nginx-proxy repo, the nginx-proxy Google Group, and the php repo. I either get no response or they pass the buck.

Upvotes: 13

Views: 14061

Answers (2)

Daniel W.
Daniel W.

Reputation: 32290

The default generated config of nginx-proxy is not fully working.

I think something is messed up with VIRTUAL_ROOT environment variable, because the root of the problem is PHP getting a wrong path via SCRIPT_FILENAME (that's why you see no PHP output) and there is no try_files with =404 symbol (that's why you get 200 with everything).

I have a prepared working setup using docker-compose in GitHub to demonstrate that it would work with an existing SCRIPT_FILENAME in the nginx config.

I have changed test.local to test.localhost.

I think to get it working as it should, you would have to use an nginx template for nginx-proxy, so the generated default.conf does work with php fpm and have the missing fastcgi param included.

Another, yet different approach would be to pack PHP and a manually configured webserver (nginx) in a project and having the automated reverse nginx proxy in a standalone project. This would cost you an additional process running but gives you more control and easier deployment.

Alternatively, you might want to have a look into traefik which does essentially the same as nginx-proxy.

Upvotes: 2

Cory Collier
Cory Collier

Reputation: 893

Daniel's answer is definitely on the right track. I use the php-fpm image with nginx as my main stack for php sites. Having said that, I don't use the nginx-proxy docker image. Instead, I use plain nginx on the host machine, and configure ports to point to backend php-fpm docker images.

I'm not using docker-compose either. Since it's just docker containers running single sites, I don't need it. Here's an example docker run command:

docker rm -f www.example.com || true
docker run -itd -p 9001:9000 -P \
        --name www.example.com \
        --volume /var/www/html/www.example.com:/var/www/html/www.example.com \
        --link mariadb:database.example.com \
        --restart="always" \
        --hostname="example.com" \
    --log-opt max-size=2m \
    --log-opt max-file=5 \
        mck7/php-fpm:7.4.x-wordpress

And here is an example nginx config:

server {
  server_name example.com www.example.com;

  location ~ /.well-known {
    allow all;
  }

  location ~ /\.ht {
    deny all;
  }

  root /var/www/html/www.example.com/src;

  index index.php;

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

  location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
      return 404;
    }

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO       $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

    fastcgi_pass   127.0.0.1:9001;
    fastcgi_index  index.php;
  }
}

A few things about this setup are key. The port re-mapping for the docker container. In this example I map port 9001 to 9000. The other "gotcha" is that the root for the container must be an actual location on the host. I have no idea why this is the case, but for whatever reason the path docker thinks it's using has to actually be the path on the host as well.

Upvotes: 2

Related Questions