PAYATHON 2026

Magento 迁移至 Gandi 后反复出现 500 error

技术老齐

结论

这种情况更可能是文件所有者或运行用户不一致,引发了缓存、会话文件的权限问题。它通常不是 Magento 数据库损坏,也不需要重新安装 Magento。

执行 magento-cleanup 后,页面能暂时恢复,但再次访问又返回 500,常见过程如下:

  1. cleanup 脚本重新设置了 var/ 等目录的权限;
  2. 第一次请求由 PHP 创建缓存、会话或锁文件;
  3. 新文件的所有者、用户组或权限与后续 Web/PHP 进程不兼容;
  4. 后续请求无法读取或覆盖这些文件,最终返回 500。

如果 .htaccess 有语法错误,或者使用了 Gandi 禁止的指令,通常第一次请求就会持续报 500,不会在执行 cleanup 后短暂恢复。因此,应先检查服务器错误日志和文件权限,而不是重装 Magento。

先查看真正的错误信息

500 只是 HTTP 层面的结果,具体原因要从日志中确认。重点检查:

  • Gandi 控制台或主机提供的 Apache/Nginx/PHP 错误日志;
  • Magento 的 var/log/system.log;
  • Magento 的 var/log/exception.log;
  • Magento 根目录下是否生成了 report/ 或 var/report/ 报告。

诊断时可以暂时在 app/Mage.php 中启用开发者模式,但不要让生产环境长期显示异常:

Mage::setIsDeveloperMode(true);
ini_set('display_errors', 1);

排查完成后要恢复原状,以免泄露文件路径、数据库信息和调用栈。

如果日志中出现以下内容,基本可以确定是权限问题:

Permission denied
failed to open stream
Unable to write
Session data file is not created
Cache directory is not writable
Cannot create lock file

修正 Magento 可写目录

Magento 1 通常要求 PHP 运行用户能够写入以下目录:

var/
media/
app/etc/

其中最需要关注的是:

var/cache/
var/session/
var/log/
var/report/
var/locks/

不要长期使用 chmod -R 777。应让站点文件归部署用户所有,并给 PHP/Web Server 的运行用户或用户组分配必要的写权限。

如果 Gandi 提供 SSH,并且已经确认 PHP 运行用户和站点用户,可以参考下面的配置:

find /path/to/magento -type f -exec chmod 644 {} \;
find /path/to/magento -type d -exec chmod 755 {} \;

chmod -R 775 /path/to/magento/var
chmod -R 775 /path/to/magento/media

如果 PHP 与部署账户属于同一用户组,还需要设置正确的用户组:

chgrp -R PHP_GROUP /path/to/magento/var
chgrp -R PHP_GROUP /path/to/magento/media

必须把 PHP_GROUP 换成 Gandi 环境中的实际用户组,不能直接套用其他主机上的 www-data、apache 等名称。

还可以为可写目录设置 setgid,让新建文件继承目录的用户组:

find /path/to/magento/var -type d -exec chmod 2775 {} \;
find /path/to/magento/media -type d -exec chmod 2775 {} \;

如果共享主机不允许执行 chown 或 chgrp,需要通过 Gandi 控制台调整 PHP 运行模式,或者联系其支持确认以下信息:

  • PHP 是以站点账户、PHP-FPM 用户还是共享 Web 用户运行;
  • PHP 创建文件时使用什么 umask;
  • Web 进程可以写入哪些目录;
  • 是否支持通过 ACL 给 PHP 用户授予写权限。

清理旧缓存和会话

权限修正后,再清理迁移过来的缓存。操作前要确认不会删除用户需要保留的文件,并尽量安排在维护窗口内执行。

Magento 缓存可以删除:

rm -rf /path/to/magento/var/cache/*

如果可以接受现有登录会话失效,也可以清理文件会话:

rm -rf /path/to/magento/var/session/*

完成后连续访问多个前台和后台页面,并检查新生成文件的所有者和权限。重点不在于 cleanup 后能否打开一次,而在于 PHP 新生成的缓存文件能否继续被后续请求读取和更新。

如果 Magento 的 session 或 cache 使用数据库、Redis、Memcached 等后端,还要检查 app/etc/local.xml 中对应服务的地址、端口和凭据,并确认相关扩展已经启用。

.htaccess 中需要注意的地方

这份 .htaccess 中没有明显能够解释“清理后只成功一次”的 RewriteRule,但确实有一些依赖服务器配置的指令。

共享主机可能不允许在 .htaccess 中修改 Options:

Options +FollowSymLinks

如果错误日志中出现:

Options not allowed here

可以按照 Gandi 的 Apache 配置改用:

Options +SymLinksIfOwnerMatch

也可以删除这一行,但前提是服务器已经在虚拟主机层启用了相应选项。

2. php_value 和 php_flag

这些指令只适用于 Apache mod_php:

php_value memory_limit 256M
php_value max_execution_time 18000
php_flag session.auto_start off

在 PHP-FPM、FastCGI 或 CGI 环境中,它们可能无效,有些配置下还会直接引发 500。不过,当前配置把它们放在以下区块中:

<IfModule mod_php5.c>

如果服务器没有加载 mod_php5,这个区块会被跳过。现代服务器也可能使用其他模块名称,因此不要依靠这里设置 PHP 参数。更稳妥的方式是在 Gandi 支持的位置配置,例如 php.ini、.user.ini 或主机控制面板:

memory_limit = 256M
max_execution_time = 300
session.auto_start = 0

对于普通网页请求,max_execution_time = 18000 过高。除非确实存在长时间运行的后台任务,否则不建议保留。

3. Apache 2.4 访问控制语法

以下配置使用的是 Apache 2.2 风格语法:

Order allow,deny
Allow from all

Apache 2.4 更适合使用:

Require all granted

文件保护规则可以写成:

<Files "RELEASE_NOTES.txt">
    Require all denied
</Files>

不过,在不了解服务器版本和兼容模块状态时,不要直接替换。如果 Gandi 加载了 mod_access_compat,旧语法仍然可以正常工作。

4. mod_security 指令

下面是较旧版本 ModSecurity 的配置:

SecFilterEngine Off
SecFilterScanPOST Off

如果服务器加载了对应模块,却不允许通过 .htaccess 关闭它,就可能返回 500。具体仍要以错误日志为准。通常不建议在应用目录中关闭整个安全模块。可以先移除这个区块进行测试,必要时请主机商针对具体规则设置例外。

5. 单独检查重定向规则

例如:

RewriteRule ^carte-des-locations-de-vacances(/.+)* /fr/carte-des-locations-de-vacances/$1 [L,R=301]

当 $1 已经以 / 开头时,目标地址中可能出现双斜杠。可以改成更清楚的写法:

RewriteRule ^carte-des-locations-de-vacances(?:/(.*))?$ /fr/carte-des-locations-de-vacances/$1 [R=301,L]

这类规则可能造成错误跳转或重定向链,但通常不会导致 cleanup 后第一次访问成功,随后又出现 500。建议先解决权限问题,再逐条检查这些规则。

快速判断是不是 .htaccess

可以临时换回对应 Magento 版本的原始 .htaccess,移除所有自定义 301 规则后测试:

  1. 保留 Magento 标准的前端控制器重写;
  2. 连续访问多个前台和后台 URL;
  3. 如果仍然是第一次正常、随后 500,继续重点检查缓存文件的所有者和 PHP 日志;
  4. 如果 500 完全消失,再分段恢复自定义配置;
  5. 每恢复一段就测试一次,以定位不兼容的指令。

不要直接删除线上 .htaccess 后就结束测试,因为 Magento 的友好 URL 通常依赖 mod_rewrite。

还应核对的迁移项目

除了权限,还要检查新旧服务器环境是否一致:

  • Magento 版本是否支持当前 PHP 版本;
  • 必要的 PHP 扩展是否已经启用;
  • mod_rewrite 是否可用,以及服务器是否允许 .htaccess 覆盖配置;
  • PHP 的 memory limit 是否足够;
  • app/etc/local.xml 中的数据库字符集和连接信息是否正确;
  • Magento Base URL 配置是否正确;
  • 文件路径的大小写是否与数据库中的类名、模块名一致;
  • media/、var/ 和临时目录是否耗尽磁盘配额或 inode;
  • PHP session 保存目录是否存在并且可写;
  • OPcache、APC 或其他 opcode cache 中是否残留旧路径。

在数据库中全局替换域名也要谨慎。Magento 的部分数据可能经过序列化,直接替换长度不同的字符串可能破坏序列化内容。核心 Base URL 通常只需要修改 core_config_data 中的对应配置,修改后再清空配置缓存。

是否需要重新安装 Magento

通常不需要。重新安装后再导入数据,无法解决 PHP 运行用户、目录权限或 .htaccess 限制,反而可能引入以下问题:

  • 模块版本不一致;
  • 数据库结构不匹配;
  • 配置遗漏;
  • 媒体文件和自定义主题丢失;
  • 序列化配置或扩展数据损坏。

建议按以下顺序处理:先查看错误日志,确认 PHP 运行用户,修正 var/ 和 media/ 的所有者及权限,然后使用原始 .htaccess 做最小化测试。只有确认应用文件或数据库已经损坏,并且没有可靠备份时,才需要考虑重新安装。

备注:内容仅供参考。