Running Python Applications Alongside PHP on Apache

php dev.to

Apache is one of the most widely used web servers because it can serve multiple technologies side by side. With mod_php, it executes PHP scripts, and with mod_wsgi, it runs Python applications. By combining these modules, you can host both languages on the same server without conflict.


Why Run PHP and Python Together?

  • PHP is often used for web APIs, CMS platforms (like WordPress), or legacy applications.
  • Python is popular for modern frameworks (Flask, Django) and data‑driven apps.
  • Running both allows you to integrate existing PHP systems with new Python services on the same infrastructure.

Step 1: Install Apache and Language Modules

Update your system:

sudo apt update
Enter fullscreen mode Exit fullscreen mode

Install Apache:

sudo apt install apache2 -y
Enter fullscreen mode Exit fullscreen mode

Install PHP with Apache support:

sudo apt install php libapache2-mod-php -y
Enter fullscreen mode Exit fullscreen mode

Install Python and WSGI module:

sudo apt install python3 python3-pip libapache2-mod-wsgi-py3 -y
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • libapache2-mod-php lets Apache interpret .php files.
  • libapache2-mod-wsgi-py3 allows Apache to run Python applications using the WSGI standard.

Step 2: Prepare Application Directories

Organize your projects under /var/www/html.

For PHP:

sudo mkdir -p /var/www/html/api
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/api/index.php
Enter fullscreen mode Exit fullscreen mode

This creates a test PHP file that shows server configuration.

For Python:

sudo mkdir -p /var/www/html/pyapp
sudo nano /var/www/html/pyapp/app.wsgi
Enter fullscreen mode Exit fullscreen mode

Add a simple WSGI app:

def application(environ, start_response):
    status = '200 OK'
    output = b"Hello from Python WSGI!"

    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    return [output]
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • PHP files are executed directly when requested.
  • Python apps need a WSGI entry point (application) that Apache calls to handle requests.

Step 3: Configure Apache

Tell Apache how to serve each type of application.

For PHP:

  • Point Apache to /var/www/html/api.
  • Any .php file in that directory will be executed by the PHP module.

For Python:

  • Use WSGIScriptAlias to map requests to the Python WSGI file (app.wsgi).
  • Apache passes incoming requests to the Python application, which returns responses.

Explanation:

Apache uses configuration rules to decide whether a request should be handled by PHP or Python. Each directory or domain can be mapped to the appropriate handler.


Step 4: Enable Modules and Reload

Enable required modules:

sudo a2enmod php7.4   # or php8.1 depending on your version
sudo a2enmod wsgi
sudo systemctl reload apache2
Enter fullscreen mode Exit fullscreen mode

Explanation:

This ensures Apache knows how to interpret both PHP and Python requests.


Step 5: Test Applications

  • Place a PHP file in /var/www/html/api and visit your PHP domain → should display PHP info.
  • Place the WSGI file in /var/www/html/pyapp and visit your Python domain → should display “Hello from Python WSGI!”.

Step 6: Secure with SSL

Install Certbot:

sudo apt install certbot python3-certbot-apache -y
Enter fullscreen mode Exit fullscreen mode

Request certificates:

sudo certbot --apache -d api.yourdomain.com -d pyapp.yourdomain.com
Enter fullscreen mode Exit fullscreen mode

Explanation:

SSL ensures traffic between your users and server is encrypted. Certbot automates certificate issuance and renewal.


Conclusion

By combining mod_php and mod_wsgi, Apache can serve both PHP and Python applications side by side. Each application runs in its own directory, and Apache routes requests to the correct interpreter. This setup is ideal for environments where legacy PHP systems coexist with modern Python services.


Source: dev.to

arrow_back Back to Tutorials