Moodle从IIS迁移至Nginx后FastCGI错误及图片404问题求助
问题现象
从Windows IIS迁移到Linux Nginx环境后,Nginx error.log频繁输出upstream prematurely closed FastCGI request while reading upstream错误,多数图片返回404无法正常显示。
错误日志片段:
2023/06/05 11:39:24 [error] 364769#364769: *4 upstream prematurely closed FastCGI request while reading upstream, client: 192.168.198.221, server: _, request: "GET /pluginfile.php?file=%2F1%2Ftheme_fordson%2Fslide1image%2F1685976991%2Funnamed%20%285%29.jpg HTTP/2.0", upstream: "fastcgi://unix:/run/php-fpm/www.sock:", host: "example.com", referrer: "https://example.com/theme/styles.php?theme=fordson&rev=1685976991_1&type=all" 2023/06/05 11:39:24 [error] 364769#364769: *4 upstream prematurely closed FastCGI request while reading upstream, client: 192.168.198.221, server: _, request: "GET /pluginfile.php?file=%2F1%2Ftheme_fordson%2Ffavicon%2F1685976991%2FUM-02.png HTTP/2.0", upstream: "fastcgi://unix:/run/php-fpm/www.sock:", host: "example.com", referrer: "https://example.com/my/"
当前配置文件
nginx.conf
user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 4096; proxy_read_timeout 300; proxy_connect_timeout 75; proxy_send_timeout 300; include /etc/nginx/mime.types; default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /etc/nginx/conf.d/*.conf; server { listen 80; listen [::]:80; server_name _; root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; rewrite ^/(.*\.php)(/)(.*)$ /$1?file=/$3 last; location /dataroot/ { internal; alias /moodle/data/moodledata/; # ensure the path ends with / } } # Settings for a TLS enabled server. server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name _; root /usr/share/nginx/html; ssl_certificate "/etc/pki/nginx/wildcard.crt"; ssl_certificate_key "/etc/pki/nginx/wildcard.key"; ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_ciphers PROFILE=SYSTEM; ssl_prefer_server_ciphers on; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; rewrite ^/(.*\.php)(/)(.*)$ /$1?file=/$3 last; location /dataroot/ { internal; alias /moodle/data/moodledata/; # ensure the path ends with / } } }
php.conf
index index.php index.html index.htm; location ~ \.php$ { try_files $uri =404; fastcgi_intercept_errors on; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass php-fpm; }
Moodle config.php
<?php // Moodle configuration file unset($CFG); global $CFG; $CFG = new stdClass(); $CFG->dbtype = 'sqlsrv'; $CFG->dblibrary = 'native'; $CFG->dbhost = '{HOST}'; $CFG->dbname = '{DBNAME}'; $CFG->dbuser = '{DBUSER}'; $CFG->dbpass = '{DBPASS}'; $CFG->prefix = 'mdl_'; $CFG->dboptions = array ( 'dbpersist' => 0, 'dbport' => '', 'dbsocket' => '', ); $CFG->wwwroot = 'https://example.com'; $CFG->dataroot = '/moodle/data/moodledata/'; $CFG->admin = 'admin'; $CFG->disableupdatenotifications = true; $CFG->xsendfile = 'X-Accel-Redirect'; $CFG->xsendfilealiases = array( '/dataroot/' => $CFG->dataroot ); $CFG->slasharguments = false; $CFG->directorypermissions = 0777; require_once(_DIR_ . '/lib/setup.php'); // There is no php closing tag in this file, // it is intentional because it prevents trailing whitespace problems!
环境信息
- PHP 7.4.33
- Nginx 1.20.1
修复方案
1. 修复config.php语法错误
config.php中require_once(_DIR_ . '/lib/setup.php');存在语法错误,正确的魔术常量是双下划线的__DIR__,该错误会直接导致PHP脚本执行失败,触发FastCGI连接中断。
修改后代码:
require_once(__DIR__ . '/lib/setup.php');
2. 添加Nginx FastCGI超时配置
当前nginx.conf仅配置了proxy相关超时,缺少FastCGI超时设置,PHP处理静态文件转发请求时易因超时中断。在http块或对应server块中添加:
fastcgi_read_timeout 300; fastcgi_connect_timeout 75; fastcgi_send_timeout 300;
3. 验证moodledata目录权限
确保Nginx进程用户(默认是nginx)拥有/moodle/data/moodledata/目录的读取权限:
chown -R nginx:nginx /moodle/data/moodledata/ chmod -R 755 /moodle/data/moodledata/
同时确认Nginx中location /dataroot/的alias路径以/结尾,与$CFG->xsendfilealiases的映射完全匹配。
4. 调整slasharguments配置
当前$CFG->slasharguments = false;与Nginx中的rewrite ^/(.*\.php)(/)(.*)$ /$1?file=/$3 last;存在解析冲突。建议开启slasharguments:
$CFG->slasharguments = true;
并移除Nginx中的上述rewrite规则,Moodle原生支持slash参数格式,无需Nginx额外重写。
5. 检查php-fpm配置一致性
确认php-fpm的www.conf中listen配置与Nginx的fastcgi_pass一致:
listen = /run/php-fpm/www.sock
同时检查pm.max_children、pm.start_servers等进程参数是否足够,避免因进程资源不足导致请求中断。
6. 验证文件路径大小写一致性
Windows系统不区分路径大小写,Linux则严格区分。检查数据库中存储的文件路径与服务器实际路径是否完全匹配,尤其是主题相关图片(如theme_fordson下的文件)的路径大小写。
内容的提问来源于stack exchange,提问作者Abraham M

