Caddy with php-fpm in docker

Hi all,

I am having a problem plugging Caddy to php-fpm. I tried many thing without success, and it’s time to get some help.


Caddy as a reverse-proxy to a PHP application served with a containerized php-fpm.
The main point here is that php-fpm is a docker container, exposing port 9000.


php-fpm does not see the php files. Only 404 are returned.

What works

Caddy successfully calls the php-fpm container.


  • It may be a permission problem, but all the user’s ID/GID are the same out and in the container
  • Caddy’s root may be the problem, I tried setting it to a relative and absolute path
  • Are rewrite rules required ?


When requesting a dumb index.php with curl -v http://localhost:8080/, php-fpm logs:

$ docker run --rm -p 9000:9000 -v $(pwd)/html:/var/www/html --user www-data --name php php:7-fpm
... -  11/Oct/2016:13:25:20 +0000 "GET /index.php" 404


  1. Create the Caddyfile below and run caddy: caddy
  2. Create a dumb index.php in the html subfolder
  3. Mount the html folder in the container when running the container: docker run --rm -p 9000:9000 -v $(pwd)/html:/var/www/html --name php php:7-fpm
  4. Test with curl: curl http://localhost:8080/

Full output


$ ./caddy
Activating privacy features... done.
11/Oct/2016:15:55:33 +0200 [ERROR 0 /index.php] Primary script unknown - [11/Oct/2016:15:55:33 +0200] "GET /index.php HTTP/1.1" 404 16

Php-fpm (running as user www-data, same result as root):

$ docker run --rm -p 9000:9000 -v $(pwd)/html:/var/www/html --name php --user www-data php:7-fpm       
[11-Oct-2016 13:57:41] NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root
[11-Oct-2016 13:57:41] NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root
[11-Oct-2016 13:57:41] NOTICE: [pool www] 'group' directive is ignored when FPM is not running as root
[11-Oct-2016 13:57:41] NOTICE: [pool www] 'group' directive is ignored when FPM is not running as root
[11-Oct-2016 13:57:41] NOTICE: fpm is running, pid 1
[11-Oct-2016 13:57:41] NOTICE: ready to handle connections -  11/Oct/2016:13:57:46 +0000 "GET /index.php" 404


$ curl -v http://localhost:8080/index.php
*   Trying
* Connected to localhost ( port 8080 (#0)
> GET /index.php HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
< HTTP/1.1 404 Not Found
< Content-Type: text/html; charset=UTF-8
< Server: Caddy
< Status: 404 Not Found
< X-Powered-By: PHP/7.0.11
< Date: Tue, 11 Oct 2016 13:55:33 GMT
< Content-Length: 16
File not found.
* Connection #0 to host localhost left intact

Caddy and Caddyfile

Repo with files: GitHub - tomsquest/caddy-with-phpfpm-docker: Sample config to reproduce a problem using Caddy fastcgi to a containerized php-fpm

$ ./caddy -version
Caddy 0.9.3
$ cat Caddyfile
root html
log stdout
errors stderr
fastcgi / localhost:9000 php


The html folder is owned locally by www-data which has the sames UID/GID as in the php-fpm container.

Local files:

$ id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)

$ ls -lRn
total 14892
drwxrwxr-x 2   33   33     4096 oct.  11 15:40 html/
-rwxrwxr-x 1 1000 1000 15224588 oct.  11 15:40 caddy*
-rw-rw-r-- 1 1000 1000       91 oct.  11 15:41 Caddyfile

total 12
-rw-rw-r-- 1 33 33 4 oct.  11 15:39 index.php

Files in php-fpm:

$ docker run --rm -p 9000:9000 -v $(pwd)/html:/var/www/html --name php php:7-fpm id www-data     
uid=33(www-data) gid=33(www-data) groups=33(www-data)

$ docker run --rm -p 9000:9000 -v $(pwd)/html:/var/www/html --name php php:7-fpm ls -lRn /var/www
total 4
drwxrwxr-x 2 33 33 4096 Oct 11 13:40 html

total 12
-rw-rw-r-- 1 33 33 4 Oct 11 13:39 index.php


$ cat html/index.php 

With Nginx

I tried successfully with Nginx talking to the same container.


$ cat docker-compose.yml 
    build: .
        - "8080:80"
        - fpm
    image: php:fpm
        - "9000:9000"

    # seems like fpm receive the full path from nginx
    # and try to find the files in this dock, so it must
    # be the same as nginx.root
        - ./:/complex/path/to/files/
$ cat Dockerfile 
FROM nginx:latest
COPY default.conf /etc/nginx/conf.d/
server {
    listen  80;

    # this path MUST be exactly as docker-compose.fpm.volumes,
    # even if it doesn't exists in this dock.
    root /complex/path/to/files;

    location / {
        try_files $uri /index.php$is_args$args;

    location ~ ^/.+\.php(/|$) {
        fastcgi_pass fpm:9000;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
1 Like

Problem solved ! :tada:

Solution: The root in the Caddyfile must be the same exact path of the volume of the docker container.

In the Caddyfile:

root /home/tom/tmp/test

Run the php-fpm volume with this path:

$ docker run -p 9000:9000 --user www-data\
    -v $(pwd):/home/tom/tmp/test/ # <-- THIS PATH is the `root`\

And the volume does not have to exist in the php-fpm container.


Hi Tom, highly recommend you study caddy-docker/Dockerfile at master · abiosoft/caddy-docker · GitHub if you haven’t already.

1 Like

Thanks for the advice @hendry . I did look at that image but:

  • I already had a Caddy in front of the docker image
  • This image is running as root, which is especially what I don’t want

Imo trying to drop privileges in a container is a painful waste of time.

The joy for containers for me, is not having to worry about perms. Worrying what user/group I should use etc etc has cost me days of my life.

Apparently the Docker Security Team disagree. But I am not an expert, they are.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.