[V2] php_fastcgi root path (For use with Docker Nextcloud)

1. Caddy version (caddy version):

Latest Docker version (v2.0.0)

2. How I run Caddy:

a. System environment:

Docker, on Debian Buster

b. Command:

docker-compose up

c. Service/unit/compose file:

services:
  caddy:
    container_name: caddy
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ../volumes/caddy/Caddyfile:/etc/caddy/Caddyfile
      - ../volumes/caddy/config:/config
      - ../volumes/caddy/data:/data
      # php-fpm roots
      - ../volumes/nextcloud/html:/php-fpm-root/nextcloud

Note the last line, where I am bind mounting the html root of nextcloud into Caddy. I do the same for the nextcloud container, but into /var/www/html/ instead of /php-fpm-root/nextcloud

d. My complete Caddyfile or JSON config:

# /etc/caddy/Caddyfile

# Global config
{
    # Let's Encrypt email
    email myemail@example.com
    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

cloud.example.com {
    root * /php-fpm-root/nextcloud/
    file_server
    php_fastcgi nextcloud:9000 {
        transport fastcgi {
            root /var/www/html/   # This doesn't work!
        }
    }
    
    header {
        # enable HSTS
        Strict-Transport-Security max-age=31536000;
    }

    redir /.well-known/carddav /remote.php/dav 301
    redir /.well-known/caldav /remote.php/dav 301

    # .htaccess / data / config / ... shouldn't be accessible from outside
    @forbidden {
            path    /.htaccess
            path    /data/*
            path    /config/*
            path    /db_structure
            path    /.xml
            path    /README
            path    /3rdparty/*
            path    /lib/*
            path    /templates/*
            path    /occ
            path    /console.php
    }
    respond @forbidden 404
}

3. The problem I’m having:

I have Caddy running in a Docker container, as well as nextcloud in a container. I have the nexctcloud html directory shared between the two containers, bind mounted at ../volumes/nextcloud/html. For the nextcloud container, this goes to /var/www/html/, whereas in the Caddy container it goes to /php-fpm-root/nextcloud/.

Back in Caddy V1, as far as I can tell you were able to do something like this:

root /php-fpm-root/nextcloud/
fastcgi / nextcloud:9000 php {
  root /var/www/html/
}

That way, Caddy serves the static files from /php-fpm-root/nextcloud/, but for fastcgi in the nextcloud container, the files are located at /var/www/html/. I see that there’s an expanded way of doing php_fastcgi, and this does seem to work, but that literally doubles the size of the Caddyfile. I was wondering if it is possible to do some sort of a root directive in the php_fastcgi directive, as you could in V1.

4. Error messages and/or full log output:

{"level":"info","ts":1589669822.9492817,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
run: adapting config using caddyfile: parsing caddyfile tokens for 'php_fastcgi': /etc/caddy/Caddyfile:38 - Error during parsing: transport already specified

{"level":"info","ts":1589670658.2529993,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
run: adapting config using caddyfile: parsing caddyfile tokens for 'php_fastcgi': /etc/caddy/Caddyfile:38 - Error during parsing: unrecognized subdirective root

5. What I already tried:

I tried the above Caddyfile (which doesn’t work, first error above), as well as:

php_fastcgi nextcloud:9000 {
    root /var/www/html/
}

(whcih also doesn’t work, second error above). I also tried the expanded form, which I think works but isn’t going to be fantastic once I add all my other php sites. I also tried just mounting the nextcloud html directory right into /var/www/html/ in Caddy, and that works too, however if any other container comes around that also uses /var/www/html/, I won’t be able to use it.

6. Links to relevant resources:

V1 was like this: https://gist.github.com/simon04/e493a1f086549b0268d412a9e3ed2669

7. Final Thoughts

This wasn’t so much a call for help as it was a question. I’d like to be able to override the root path for php_fastcgi, without having to rewrite the whole thing in expanded form. Is that possible?

1 Like

Hmm. That’s a very interesting problem! I’ll dig into the Caddy code and try to figure out why it doesn’t work. I agree with you that it probably should.

Thanks for filling out the template and the very clear explanation and for explaining your usecase!

1 Like

Oh geez. Yeah so like you said, the clue was that it works using the expanded form. Thanks for going the extra mile and trying that!

This should be solved in the v2.1 release, I wrote a PR to allow passthrough of the fastcgi transport options when using the php_fastcgi shortcut:

It’ll look like this:

    php_fastcgi nextcloud:9000 {
        root /var/www/html/
    }

So yeah, I guess you have two options to work around it for now until the v2.1 release, like you said. Either use the expanded form, or change the volume mount. :+1:

1 Like

Actually, if you’re willing to help test that PR, it would be a big help.

All you’d need to do is download the CI build artifact and mount the new Caddy binary to /usr/bin/caddy in the container to override the existing one in the container. Just temporarily to test :smile:

The CI run is here:

1 Like

Looks good to me! I was able to just use the following:

    root * /php-fpm-root/nextcloud/
    file_server
    php_fastcgi nextcloud:9000 {
        root /var/www/html/
    }

and Nextcloud loads up just fine! Thanks for the quick fix! I’m excited to move over to Caddy since I like how simple the config is, and since it also serves static files I can cut down on the many nginx containers running behind my current reverse proxy.

Another quick question if you don’t mind, I see that the URL looks like this:

https://cloud.example.com/index.php/apps/files/?dir=/&fileid=164

Is there some other option I am missing to remove that /index.php portion of the URL, so it instead looks like this to the user:

https://cloud.example.com/apps/files/?dir=/&fileid=164

Thank you!

1 Like

Hmm. That might be a side effect of the separate roots. That’s interesting. I think NextCloud is doing that though, not Caddy. I think both should work though, just that NextCloud generates links to /index.php instead, I think.

Yeah, didn’t know if it was Nextcloud or Caddy. The Nextcloud Docker image with Apache included had a setting to rewrite the URL, so I’m not sure what the php_fpm version has. I’ll have to investigate. Thanks for your help!

1 Like

I’m really curious about this. To be clear, I do this, too. But I just reverse proxy to the container, I don’t mount site files and have Caddy handle the PHP.

You’re mounting the Nextcloud site yourself. Nextcloud is just a PHP app (albeit an incredibly comprehensive one). The advantage of running Nextcloud in a container is that you don’t need to set up your web server for it, you can just reverse proxy to it (or expose it directly) - it’s a turn-key solution that produces a HTTP endpoint with a working Nextcloud for you. So, why have the container AND mount the site files?

My answer is two fold. One, I love tinkering, and wanted to try something new!

The more serious second answer is because I wanted to cut down on server processes/containers. With the standard Apache Nextcloud docker image and a reverse proxy, I had a minimum of 3 processes (Nextcloud container had Apache and php, proxy was nginx). Using the fpm Nextcloud image and caddy, that’s now just 2 processes (caddy doing its thing, and the Nextcloud container has a custom version of php-fpm). That might not sound like much, but I also have other containers that are just a web server and php wrapped up. In my mind there’s no sense in having a reverse proxy to a web server to php, if I can cut the middle man out by using a php-fpm container instead.

Granted, it’s probably easier to just have the Apache Nextcloud container and reverse proxy to it. But I think in my use case Nextcloud feels more snappy. Maybe because it’s not going through two layers of web servers? I dunno. But I figured if I could pull this off I could pretty much get anything behind Caddy working correctly, and thus reduce the number of containers I was using.

Using caddy now I was able to reduce my reverse proxy containers from 4 containers down to 1, as well as get 4 of my static/php sites served directly from caddy instead of a reverse proxied web server. I’m pretty happy about that!

3 Likes

Specifically, I think if you want Caddy to serve up Nextcloud directly (which is totally fine), you’d be better off just copying out the Nextcloud directory from the Nextcloud container itself and running it entirely in the Caddy container. You don’t even need a Nextcloud container if all it’s doing is providing some files in a volume. Run your own neat little php container too - https://hub.docker.com/_/php.

I thought so too, but it turns out if you do that, you need to add a bunch of php modules and change some php settings (default php image doesn’t even come with mysqlnd for example). The Nextcloud image (with fpm tag, not the latest/Apache one) has this php preconfigured with all the php modules it specifically needs. Additionally, it keeps the Nextcloud static files up to date automatically.

1 Like

Aha, that’s cool. I understand now. That’s quite nice!