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.phpjust produces “File not found.”- Remove
root * /data/host/skeleton/app/publicline from my Caddyfile. Now the domain root responds with404. “File not found.” message still happens when visiting/index.php. - Add
index index.php,split .phpandroot /data/host/skeleton/app/publicinside myphp_fastcgiroute configuration. This had no effect, because the standardphp_fastcgidirective already has these values set as default. - Set permissions again, just for sure:
chmod -R 775 /data/host/skeleton- Note:
/data/hostis owned bywww-datatoo.
- Note:
chown -R www-data:www-data /data/host/skeleton- I also ensured that
/run/php/php-fpm.skeleton.sockhas 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.phpaway and create a new one that just outputs phpinfo(). Same behavior. - Create a dummy
.txtfile withwww-dataowner & 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_serverdirective 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.linkinstead of subdomain (skeleton.kevo.link), which resulted in the same behavior. - (see 2.b) Ran Caddy as
rootuser outsidesystemd. This madefile_serverserve non-PHP files properly, however the issue withindex.phpwasn’t fixed (still “File not found.”). This leaves me to believe that Caddy’sfile_serverhas indeed problems with permissions, but it makes no sense to me since all relevant directories are owned by the user thatsystemdCaddy runs as,
sowww-data(?). - Lastly, I set
/data/host/skeletonrecursively to permission777and restarted both Caddy and PHP-FPM (systemd). This changed nothing, and/still responds with403&/index.phpsays “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)
