Hi everyone,
I am part of a team that provides hosting for one forum software. I’m currently taking a look at Caddy (as a replacement for Nginx). I’m trying it for the first time, but I must say, I am impressed. I was able to reverse proxy to our Python Gunicorn backend with no issues and a few lines of configuration. However, the forum software that we are using is written in PHP - thus, we need to use PHP-FPM with Caddy to serve requests. And that’s where I got stuck.
1. Caddy version (caddy version
):
v2.4.6 h1:HGkGICFGvyrodcqOOclHKfvJC0qTU7vny/7FhYp9hNw=
Using PHP 8.0.14
2. How I run Caddy:
a. System environment:
Ubuntu 20.04.3 LTS focal
b. Command:
I tried to run it as root
with the following commands instead as well. This helped with file_server
(see later below, 5.9.*):
cd /etc/caddy
caddy run
c. Service/unit/compose file:
/etc/systemd/system/caddy.service:
[Unit]
Description=Caddy web server
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target
[Service]
Type=notify
User=www-data
Group=www-data
ExecStart=/usr/bin/caddy run --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
d. My complete Caddyfile or JSON config:
skeleton.kevo.link {
root * /data/host/skeleton/app/public
php_fastcgi unix//run/php/php-fpm.skeleton.sock
header /assets {
+Cache-Control "public, must-revalidate, proxy-revalidate"
+Cache-Control "max-age=25000"
Pragma "public"
}
file_server
}
My PHP-FPM pool config, if that helps:
[skeleton]
prefix = /data/host/skeleton/app/public
user = www-data
group = www-data
listen = /run/php/php-fpm.skeleton.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 3
pm.process_idle_timeout = 60s
pm.max_requests = 300
chroot = /data/host/skeleton/
catch_workers_output = yes
php_admin_value[session.save_path] = /sessions
Note that I am running PHP-FPM in chroot
- however, removing that line doesn’t help.
3. The problem I’m having:
When visiting the site root, Caddy responds with 403
(https://skeleton.kevo.link
) - this status code is weirdly not logged anywhere in Caddy (checked with tail -n 500 /var/log/www/caddy.log | grep 403
).
Visiting https://skeleton.kevo.link/index.php
results in 404
and “File not found.” text.
4. Error messages and/or full log output:
I am running both Caddy and PHP-FPM in debug mode. PHP-FPM outputs this error:
WARNING: pid 1021482, (null)(), line 0: [pool skeleton] child 1021549 said into stderr: "DEBUG: main(), line 1872: Primary script unknown"
As for Caddy, this relevant information was logged:
{"level":"debug","ts":1641316561.8956215,"logger":"http.reverse_proxy.transport.fastcgi","msg":"roundtrip","request":{"remote_addr":" ... ","proto":"HTTP/2.0","method":"GET","host":"skeleton.kevo.link","uri":"/index.php","headers":{ ... },"tls":{"resumed":true,"version":772,"cipher_suite":4865,"proto":"h2","proto_mutual":true,"server_name":"skeleton.kevo.link"}},"dial":"/run/php/php-fpm.skeleton.sock","env":{ ... "REQUEST_URI":"/index.php",
"SCRIPT_FILENAME":"/index.php","SCRIPT_NAME":"/index.php", <--- culprits(?)
"SERVER_NAME":"skeleton.kevo.link","SERVER_PROTOCOL":"HTTP/2.0","SERVER_SOFTWARE":"Caddy/v2.4.6","SSL_CIPHER":"TLS_AES_128_GCM_SHA256","SSL_PROTOCOL":"TLSv1.3"}}
{"level":"debug","ts":1641316561.9118648,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"unix//run/php/php-fpm.skeleton.sock","duration":0.016688851,"request":{"remote_addr":"...","proto":"HTTP/2.0","method":"GET","host":"skeleton.kevo.link","uri":"/index.php","headers":{ ... },"tls":{"resumed":true,"version":772,"cipher_suite":4865,"proto":"h2","proto_mutual":true,"server_name":"skeleton.kevo.link"}},"headers":{"Content-Type":["text/html; charset=UTF-8"],"Status":["404 Not Found"]},"status":404}
5. What I already tried:
-
sudo -u www-data caddy run
- run Caddy outside of systemd. Didn’t help. Visiting the root path (https://skeleton.kevo.link/
) responds again with403
, andhttps://skeleton.kevo.link/index.php
just produces “File not found.” - Remove
root * /data/host/skeleton/app/public
line from my Caddyfile. Now the domain root responds with404
. “File not found.” message still happens when visiting/index.php
. - Add
index index.php
,split .php
androot /data/host/skeleton/app/public
inside myphp_fastcgi
route configuration. This had no effect, because the standardphp_fastcgi
directive already has these values set as default. - Set permissions again, just for sure:
-
chmod -R 775 /data/host/skeleton
-
Note:
/data/host
is owned bywww-data
too.
-
Note:
chown -R www-data:www-data /data/host/skeleton
- I also ensured that
/run/php/php-fpm.skeleton.sock
has user and groupwww-data
:
srw-rw---- 1 www-data www-data 0 Jan 5 11:33 /run/php/php-fpm.skeleton.sock
-
- Move old
index.php
away and create a new one that just outputs phpinfo(). Same behavior. - Create a dummy
.txt
file withwww-data
owner & group to see if Caddy can serve that file properly, and that outputs another 403 that wasn’t logged (Caddy just outputs a debug info that the root path was sanitized, nothing else that’s relevant to that request:{"level":"debug","ts":1641382775.3904107,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/data/host/skeleton/app/public","request_path":"/dummy.txt","result":"/data/host/skeleton/app/public/dummy.txt"}
) - Remove
file_server
directive from my Caddyfile. That made all sites except forindex.php
(which had the same behavior) blank (makes sense). However, requests to the blank sites were not logged in both Caddy and PHP-FPM (or at least I couldn’t find anything that’s relevant to that requests in my logs). - Changed Caddyfile to listen to
kevo.link
instead of subdomain (skeleton.kevo.link
), which resulted in the same behavior. -
(see 2.b) Ran Caddy as
root
user outsidesystemd
. This madefile_server
serve non-PHP files properly, however the issue withindex.php
wasn’t fixed (still “File not found.”). This leaves me to believe that Caddy’sfile_server
has indeed problems with permissions, but it makes no sense to me since all relevant directories are owned by the user thatsystemd
Caddy runs as,
sowww-data
(?). - Lastly, I set
/data/host/skeleton
recursively to permission777
and restarted both Caddy and PHP-FPM (systemd
). This changed nothing, and/
still responds with403
&/index.php
says “File not found.”
I’ve spend so much time trying to figure out what’s wrong now, and I am desperate. I don’t know why a 403 is sent and why PHP-FPM isn’t working.
I guess that it might be an issue with PHP-FPM and permissions, however the same setup works with Nginx (I checked that the permissions and PHP-FPM configurations are the same as they’re at the production server that’s using Nginx, but I admit that I might’ve missed something).
My goal is to visit the site root and forward traffic to PHP-FPM (without having to type /index.php
in uri). Could you please guide me what I did wrong?
6. Links to relevant resources:
- Caddy with PHP-FPM - File not found - Help - Caddy Community
- 403 Forbidden for static files - Help - Caddy Community
-
Cannot get PHP working · Issue #4181 · caddyserver/caddy (github.com)
…and more (but I could only attach 4 links to my message, apologies)