Django/Apache/mod_wsgi Deployment Issue: Internal Server Error & Redirect Loop on cPanel (AlmaLinux 9)

I'm an intern trying to deploy a Django application on a cPanel server, and I’ve run into a persistent “Internal Server Error” coupled with an Apache redirect loop. I’ve been troubleshooting for over two days with various AI helpers, but I can’t pinpoint the exact cause. Any fresh perspectives ??


My Setup:

  • Server OS : AlmaLinux 9.6 (Sage Margay)
  • Hosting Environment: cPanel (My cPanel account does not have the “Setup Python App” option, which is why I’m using a manual Apache/mod_wsgi configuration.)
  • Django Deployment: Apache + mod_wsgi
  • No .htaccess content at all.
  • Project Structure: I have two Django instances (production and staging) for CI/CD,

each with its own settings, environment variables, database, and domain.

  • validator/settings/base.py

  • validator/settings/production.py (inherits from base)

  • validator/settings/staging.py (inherits from base)

  • Environment files are stored in /etc/validator/envs

  • WSGI files are stored in /etc/validator/wsgi/

  • Django project roots: /home/<username>/<app_name>/ (prod) and /home/<username>/<app_name_test>/ (staging).

  • Python Version: My virtual environments are running Python 3.12.9, and my WSGI files assert this.


The Problem:

When I try to access either domain.in (production) or test.domain.in (staging),
I receive an “Internal Server Error”. My Apache error log (specifically /var/log/httpd/error_log) shows the following critical error message:

[Fri May 30 00:26:38.624027 2025] [core:error] [pid 253617:tid 253705] [client 45.115.89.80:26970] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.

This started after a server expiration/renewal and then when I configured new databases for staging and production, updating the respective .env files. Previously, it worked (sharing a database).


My Apache configuration:

I understand cPanel uses a “Direct Include Style” for Apache configs, where httpd.conf includes files from directories like /etc/apache2/conf.d/userdata/.... My custom Django configurations are placed in these included directories.

  1. Production Domain Custom Apache Config (/etc/apache2/conf.d/userdata/std/2_4/<username>/<domain.in>/<filename>.conf):
ServerName <domain>.in
ServerAlias www.<domain>.in
ServerAlias <server_ip>

WSGIDaemonProcess django_app python-home=/home/<username>/app/venv python-path=/home/<username>/app user=<apache_user> group=<group_user>
WSGIProcessGroup app

WSGIScriptAlias / /etc/validator/wsgi/production.wsgi 

Alias /static/ /home/<username>/app/staticfiles/

<Directory /home/<username>/app/staticfiles>
        Require all granted
</Directory>

<Directory /etc/validator/wsgi>
        <Files production.wsgi>
            Require all granted
        </Files>
</Directory>

ErrorLog /home/<username>/app/error.log
CustomLog /home/<username>/app/access.log combined
  1. Staging Domain Custom Apache Config (similar path for test.domain.in):
ServerName test.<domain>.in
ServerAlias www.test.<domain>.in

WSGIDaemonProcess test_app python-home=/home/<username>/app_test/venv python-path=/home/<username>/app_test user=<apache_user> group=<group_user>
WSGIProcessGroup app_test

WSGIScriptAlias / /etc/validator/wsgi/staging.wsgi 

Alias /static/ /home/<username>/app_test/staticfiles/

<Directory /home/<username>/app_test/staticfiles>
        Require all granted
</Directory>

<Directory /etc/validator/wsgi>
        <Files production.wsgi>
            Require all granted
        </Files>
</Directory>

ErrorLog /home/<username>/app_test/error.log
CustomLog /home/<username>/app_test/access.log combined

3.Production Environment File (/etc/validator/envs/production.env):

DBUSER=<dbuser>
DBPASSWORD=<dbpasswd>
DBNAME=<dbname>
DBHOST=localhost
DBPORT=3306
  1. Production WSGI File (/etc/validator/wsgi/production.wsgi):
import os
import sys
from pathlib import Path
from dotenv import load_dotenv

ENV_FILE = Path('/etc/validator/envs/production.env')
load_dotenv(dotenv_path=ENV_FILE)

os.environ.setdefault('DJANGO_SETTINGS_MODULE', '<django_root_app>.settings.production')

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
  1. Django settings/prod.py (similar structure for settings/staging.py):
import os
from .base import *

DEBUG = False

ALLOWED_HOSTS = [
    "domain",
    "www.domain",
    "server_ip",
]

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.<sql>",
        "USER": os.environ["DBUSER"],
        "PASSWORD": os.environ["DBPASSWORD"],
        "NAME": os.environ["DBNAME"],
        "HOST": os.environ["DBHOST"],
        "PORT": os.environ["DBPORT"],
    }
}

Troubleshooting Steps I’ve Already Taken:

  1. Checked Apache Error Logs: The main Apache log (/var/log/httpd/error_log) consistently shows the “Request exceeded the limit of 10 internal redirects” error. My Django app’s custom logs (/home//app/error.log and _test/error.log) are empty or show no relevant errors, often indicating a problem before Django’s logger can even kick in.

  2. Permissions: I’ve meticulously checked and set chown -R medivali:webapps and chmod permissions (755 for directories, 644 for files, 664 for logs) on /home//app/, /home//app_test/, /etc/validator/envs/, and /etc/validator/wsgi/.

  3. WSGIDaemonProcess User/Group: I’ve tried user=nobody group=webapps (as in config) and user=medivali group=medivali. Neither resolves the issue.

  4. Python Version Assertion: Confirmed venv/bin/python --version is 3.12+ for both environments.

  5. proxy_fcgi_module Conflict: I’ve added <FilesMatch “.(phtml|php[0-9]*)$”>SetHandler None to my validator_conf.conf files to try and prevent the cPanel PHP-FPM handler from interfering.

  6. DocumentRoot vs. WSGIScriptAlias: I understand WSGIScriptAlias / should override DocumentRoot for Django, but I’ve also tried creating an index.html in /home/medivali/public_html (the default DocumentRoot in the main VHost) to test basic Apache serving, but it still leads to the redirect loop or internal server error.

  7. Database Credentials: I’ve triple-checked the DBUSER, DBPASSWORD, DBNAME, DBHOST, DBPORT in both .env files. I can connect to the databases directly from the server using mysql client.

  8. ALLOWED_HOSTS: Confirmed correct domain names are in ALLOWED_HOSTS for both production and staging settings.

  9. AI Consultations: Spent 2.5 days consulting ChatGPT, Gemini, Claude, and DeepSeek, trying various suggestions, but without success.

It’s been more than 10 years since I’ve configured an Apache server to run Django, so I’m not sure how relevant these items may be - but I’m tossing them out anyway.

You might also want to try increasing the Apache log level to see if you can get more detailed information, and/or try a very trivial application just to verify the functionality. (see Troubleshooting — mod_wsgi 5.0.2 documentation)