2025, Dec 20 09:02
Internal Server Error при деплое Django на cPanel с Apache/mod_wsgi: виноват Python
Как мы исправили Internal Server Error (AH00124) при деплое Django на cPanel с Apache/mod_wsgi: проблема в сборке Python и C‑расширениях, а не в Apache.
Развертывание Django на cPanel с Apache/mod_wsgi: поиски Internal Server Error, который оказался не в Apache
Развертывание приложения Django на сервере cPanel с Apache и mod_wsgi кажется простым — пока внезапно не перестает таким быть. В нашем случае проявлялась упрямая «Внутренняя ошибка сервера» (Internal Server Error) вместе с сообщением Apache о превышении лимита внутренних перенаправлений. Окружение состояло из двух изолированных инстансов Django — production и staging — с отдельными базами данных и env‑файлами. Настройка Apache/mod_wsgi была выполнена вручную, поскольку в аккаунте cPanel не было функции Setup Python App. До продления сервера и переконфигурирования баз приложение работало, но после этого оба домена падали с одной и той же ошибкой.
Журнал ошибок Apache был однозначен в одном: сервер считал, что попал в цикл. Он выдавал хорошо известное сообщение AH00124. Файлов .htaccess с правилами не было, а собственные логи приложения либо пустовали, либо не успевали ловить что‑то полезное, что намекало: запрос даже не доходит до подсистемы логирования Django.
Как была устроена конфигурация
Развертывание опиралось на Direct Include Style в cPanel, когда httpd.conf подключает дополнительные пользовательские конфиги. Ниже — ключевые элементы: подключение WSGI‑приложений, маршрутизация статики и WSGI‑входная точка, которая читает переменные окружения и выставляет корректный модуль настроек Django. Имена отличаются от оригинала, но поведение то же.
ServerName example.in
ServerAlias www.example.in
ServerAlias 203.0.113.10
WSGIDaemonProcess svc_main python-home=/home/user/app/venv python-path=/home/user/app user=apacheuser group=appgroup
WSGIProcessGroup grp_main
WSGIScriptAlias / /etc/validator/wsgi/prod.wsgi
Alias /static/ /home/user/app/staticfiles/
<Directory /home/user/app/staticfiles>
Require all granted
</Directory>
<Directory /etc/validator/wsgi>
<Files prod.wsgi>
Require all granted
</Files>
</Directory>
ErrorLog /home/user/app/error.log
CustomLog /home/user/app/access.log combinedСтендовая инстанция повторяла подход с собственным venv, путями и WSGI‑файлом.
ServerName test.example.in
ServerAlias www.test.example.in
WSGIDaemonProcess svc_stage python-home=/home/user/app_stage/venv python-path=/home/user/app_stage user=apacheuser group=appgroup
WSGIProcessGroup grp_stage
WSGIScriptAlias / /etc/validator/wsgi/stage.wsgi
Alias /static/ /home/user/app_stage/staticfiles/
<Directory /home/user/app_stage/staticfiles>
Require all granted
</Directory>
<Directory /etc/validator/wsgi>
<Files stage.wsgi>
Require all granted
</Files>
</Directory>
ErrorLog /home/user/app_stage/error.log
CustomLog /home/user/app_stage/access.log combinedWSGI‑входная точка подгружала нужный env‑файл и выбирала целевой модуль настроек.
import os as osmod
import sys as sysmod
from pathlib import Path as Pth
from dotenv import load_dotenv as loadenv
ENV_PATH = Pth('/etc/validator/envs/production.env')
loadenv(dotenv_path=ENV_PATH)
osmod.environ.setdefault('DJANGO_SETTINGS_MODULE', 'coreapp.settings.production')
from django.core.wsgi import get_wsgi_application as get_app
application = get_app()Продакшен‑настройки использовали переменные окружения для подключения к базе данных и отключали DEBUG. Имена в Django оставлены как есть; импорты и локальные имена адаптированы без изменения поведения.
import os as osmod
from .base import * # noqa
DEBUG = False
ALLOWED_HOSTS = [
'example',
'www.example',
'203.0.113.10',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlbackend',
'USER': osmod.environ['DBUSER'],
'PASSWORD': osmod.environ['DBPASSWORD'],
'NAME': osmod.environ['DBNAME'],
'HOST': osmod.environ['DBHOST'],
'PORT': osmod.environ['DBPORT'],
}
}Что на самом деле говорил сервер
Apache многократно сообщал, что превышен лимит рекурсии для внутренних перенаправлений.
AH00124: Запрос превысил лимит из 10 внутренних перенаправлений из-за вероятной ошибки конфигурации. При необходимости используйте 'LimitInternalRecursion', чтобы увеличить лимит. Установите 'LogLevel debug', чтобы получить обратную трассировку.
Без RewriteRule в .htaccess и без какой‑либо пользовательской логики перенаправлений в показанных фрагментах это указывало на цикл на веб‑уровне, в то время как приложение молчало. В этом и заключался парадокс: Apache был уверен, что зациклился, а Django не оставлял ни следа.
Корневая причина
Несмотря на «редиректные» подсказки в логах, истинной проблемой оказалась сборка Python. Некоторые модули с C‑расширениями, в том числе используемые pickle, были собраны некорректно. Из‑за этого рантайм под mod_wsgi ломался и приводил к Internal Server Error. Корректная пересборка окружения устранила сбой.
Как это исправили
Решение — пересобрать Python‑окружение так, чтобы необходимые C‑расширения корректно компилировались. Менять блоки vhost в Apache, WSGI‑входные точки или настройки Django не потребовалось для устранения проблемы.
Почему это важно для Django на cPanel с mod_wsgi
Сообщения инфраструктуры могут вводить в заблуждение, если рантайм приложения падает, не успев ничего залогировать. Можно увидеть предупреждение AH00124 о редиректах и при этом столкнуться с проблемой на более низком уровне — в интерпретаторе Python или его расширениях. Когда WSGI‑процесс гибнет на старте, Apache может отдать общий Internal Server Error, а контекст вокруг будет намекать на ошибку в HTTP‑настройках, хотя истинная причина — в сборке Python.
Это особенно актуально, когда вы запускаете несколько инстансов Django с отдельными виртуальными окружениями, раздельными WSGI‑файлами и доменными include‑конфигами Apache. Каждое окружение должно быть здорово само по себе. Если после продления сервера или перекомпоновки зависимостей меняются исходные предпосылки о Python‑тулчейне, легко начать отлаживать не тот уровень.
Итоги и заключение
Если при деплое на mod_wsgi вы ловите Internal Server Error, а Apache утверждает, что упирается в предел внутренних перенаправлений, не ограничивайтесь проверкой веб‑серверных правил. Проверьте, что Python‑рантайм и C‑расширения, от которых зависит ваш стек, собраны корректно. В конфигурациях с cPanel, где вы вручную настраиваете WSGI‑демоны и доменные конфиги, веб‑слой может быть в порядке, а интерпретатор под ним — нет. После пересборки Python‑окружения и правильной компиляции расширений развертывание снова заработало.