Of course. Using Python 2.7 with mod_wsgi is a common task, especially when maintaining legacy applications. Here’s a comprehensive guide covering the installation, configuration, and best practices.

Important Disclaimer: Python 2.7 is End-of-Life
Python 2.7 reached its official end-of-life on January 1, 2025. This means:
- No Security Updates: Your application is vulnerable to known security flaws.
- No Bug Fixes: Issues will not be resolved.
- No New Features: You will miss out on improvements and language enhancements in Python 3.
Strong Recommendation: The best long-term solution is to migrate your application to Python 3. However, if you absolutely must use Python 2.7 for a legacy system, this guide will help you do it correctly.
Installation of mod_wsgi
The installation process depends on your operating system.
For RHEL / CentOS / Fedora (using yum or dnf)
This is the most common and straightforward method for these systems.

# For Python 2.7, the package is typically named mod_wsgi-python27 sudo yum install mod_wsgi-python27 # Or on newer systems using dnf: # sudo dnf install mod_wsgi-python27
For Debian / Ubuntu (using apt)
The default libapache2-mod-wsgi package often points to the latest Python version (e.g., Python 3). You need to explicitly install the Python 2.7 version.
# Update your package list sudo apt-get update # Install the Python 2.7 version of mod_wsgi sudo apt-get install libapache2-mod-wsgi-py27 # Enable the module (it might be enabled by default, but this ensures it) sudo a2enmod wsgi
Manual Installation from Source
If a pre-built package is not available for your specific system or Python version, you can compile it from source.
Prerequisites: You'll need the Python 2.7 development headers and Apache development libraries.
- On Debian/Ubuntu:
sudo apt-get install python2.7-dev apache2-dev
- On RHEL/CentOS:
sudo yum install python27-devel httpd-devel
Compilation Steps:

# Download the source code (check for the latest version on PyPI) wget https://files.pythonhosted.org/packages/source/m/mod_wsgi/mod_wsgi-4.9.4.tar.gz tar -xvf mod_wsgi-4.9.4.tar.gz cd mod_wsgi-4.9.4 # IMPORTANT: Explicitly tell the installer to use Python 2.7 # Replace '/usr/bin/python2.7' with your actual Python 2.7 path if different ./configure --with-python=/usr/bin/python2.7 # Compile and install make sudo make install
After manual installation, you may need to create a symbolic link for Apache:
# Find where apxs is located which apxs # It's often in /usr/sbin/apxs. Create the config file link sudo ln -s /usr/lib64/httpd/modules/mod_wsgi.so /etc/httpd/modules/mod_wsgi.so # Or on 32-bit systems: # sudo ln -s /usr/lib/httpd/modules/mod_wsgi.so /etc/httpd/modules/mod_wsgi.so
Creating a Simple WSGI Application
Let's create a basic "Hello, World!" application to test our setup.
-
Create a project directory:
mkdir /var/www/my_legacy_app cd /var/www/my_legacy_app
-
Create the WSGI script file (
app.wsgi): This file will be the entry point for your application.# /var/www/my_legacy_app/app.wsgi import sys import os # Add the project directory to the Python path # This allows you to import modules from your project sys.path.append('/var/www/my_legacy_app') # Set an environment variable for the application (optional but good practice) os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings' # Example for Django # os.environ['APP_CONFIG'] = 'production' # Import your application object or callable # For a simple app: def application(environ, start_response): status = '200 OK' output = 'Hello World from Python 2.7 and mod_wsgi!\n' response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(output)))] start_response(status, response_headers) return [output] # For a framework like Flask (make sure you have Flask installed for py2.7) # from myapp import app as application # 'application' is the standard name
Configuring Apache
Now, you need to tell Apache to use your WSGI application.
-
Create an Apache configuration file: A good practice is to create a new config file in
conf-availableorconf.d.- On Debian/Ubuntu:
sudo nano /etc/apache2/sites-available/legacy_app.conf
- On RHEL/CentOS:
sudo nano /etc/httpd/conf.d/legacy_app.conf
- On Debian/Ubuntu:
-
Add the following configuration:
<VirtualHost *:80> ServerName your-domain.com # Replace with your domain or IP ServerAdmin admin@your-domain.com # DocumentRoot is not used for a pure WSGI app # DocumentRoot /var/www/my_legacy_app # WSGI script alias # This maps the URL / to your WSGI script file WSGIScriptAlias / /var/www/my_legacy_app/app.wsgi # Directory permissions <Directory /var/www/my_legacy_app> Order allow,deny Allow from all # For Apache 2.4+ use 'Require all granted' instead # Require all granted </Directory> # Optional: Set WSGI process settings # This runs your application in a "daemon mode" process, which is recommended # for performance and stability. WSGIDaemonProcess my_legacy_app \ python-path=/var/www/my_legacy_app \ python-home=/path/to/your/virtualenv # Highly recommended! WSGIProcessGroup my_legacy_app </VirtualHost>
Explanation of Key Directives:
WSGIScriptAlias / /path/to/app.wsgi: This is the most important directive. It tells Apache that any request to the root URL () should be handled by the WSGI script located at/path/to/app.wsgi.WSGIDaemonProcess: This defines a group of daemon processes that will run your WSGI application.python-path: Adds your project directory tosys.path, so you can import local modules.python-home: (Highly Recommended) Points to the root of a Python virtual environment. This isolates your application's dependencies, preventing conflicts with system packages.
WSGIProcessGroup: This tells Apache to use the daemon processes defined byWSGIDaemonProcessto handle requests for this virtual host.
Using a Virtual Environment (Best Practice)
Isolating your project's dependencies is crucial. Here's how to set it up.
-
Install
virtualenvfor Python 2.7:pip install virtualenv
-
Create a virtual environment in your project directory:
cd /var/www/my_legacy_app virtualenv --python=python2.7 venv
This creates a
venvdirectory containing a self-contained Python 2.7 installation. -
Activate it and install dependencies:
source venv/bin/activate pip install --upgrade pip pip install flask sqlalchemy # Example packages deactivate
-
Update your Apache config (
legacy_app.conf): Modify theWSGIDaemonProcessdirective to point to the virtual environment's Python interpreter.WSGIDaemonProcess my_legacy_app \ python-path=/var/www/my_legacy_app \ python-home=/var/www/my_legacy_app/venv # <-- POINT TO VENV
Final Steps and Troubleshooting
-
Enable the site and restart Apache:
- On Debian/Ubuntu:
sudo a2ensite legacy_app.conf sudo service apache2 restart
- On RHEL/CentOS:
sudo service httpd restart
- On Debian/Ubuntu:
-
Test it: Open your web browser and navigate to
http://your-domain.com/. You should see "Hello World from Python 2.7 and mod_wsgi!".
Common Troubleshooting Tips:
-
Internal Server Error (500):
- Check Apache Error Logs: This is your best friend.
- Debian/Ubuntu:
/var/log/apache2/error.log - RHEL/CentOS:
/var/log/httpd/error_log
- Debian/Ubuntu:
- Common causes:
- Syntax error in your
app.wsgior Python code. - Missing Python packages (use the virtual environment!).
- Incorrect file permissions. Apache (
www-dataon Debian,apacheon CentOS) needs read/execute permissions on theapp.wsgifile and the project directory.sudo chown -R www-data:www-data /var/www/my_legacy_app sudo chmod -R 755 /var/www/my_legacy_app
- Syntax error in your
- Check Apache Error Logs: This is your best friend.
-
Forbidden Error (403):
- Almost always a permissions issue. Check the logs and the
<Directory>block in your Apache config to ensureAllow from allorRequire all grantedis set.
- Almost always a permissions issue. Check the logs and the
-
WSGI Module Not Found:
- Ensure
mod_wsgiis enabled:sudo a2enmod wsgi. - If you compiled from source, ensure the
mod_wsgi.sofile is in the correct Apache modules directory and that Apache is looking there. Check yourhttpd.conffor aLoadModuledirective.
- Ensure
