4

(Important) Disclaimer: I know it's probably not a good idea, that Python is not like PHP, and that the "natural" way to do web with Python is more by using a framework like Bottle, Flask, Django (that I already use), etc. But still, just out of curiosity, I'd like to see how the following is possible.


When Apache + PHP are installed, we can access a page like http://www.example.com/index.php. Internally, Apache probably passes the request to PHP which executes code, produces a text output, which is then served by Apache.

Question: how could we do something similar in Python? i.e. by accessing http://www.example.com/index.py, Apache would call the script index.py:

print("<html><body>Hello world</body></html>")

and then Apache would serve this page to the client.


NB:

  • Calling http://www.example.com/index.py?foo=bar could even give the params to the Python script in sys.argv

  • I already did it like this: http://www.example.com/index.php:

    <?php 
    $out = shell_exec("python index.py"); 
    echo($out); 
    ?>
    

    which then calls the Python script and produces the output. It works, but I'd like to do it without PHP.

  • Said in another way, is there something like mod_php for Python?

Basj
  • 41,386
  • 99
  • 383
  • 673
  • apache has module `mod_python` to run python script and also `mod_fcgi` to run script in any language (ie. python, perl, ruby, bash). – furas Oct 16 '19 at 13:11
  • 1
    check [Python - CGI programming](https://www.tutorialspoint.com/python/python_cgi_programming.htm) to see how to write code for `mod_fcgi` – furas Oct 16 '19 at 13:29
  • Note about bounty (I forgot to add a note): `mod_python` is often cited as non-maintained-anymore. Is there nowadays a good solution that **does not** require a Python framework, and **does not require** a constantly running script listening on a port. Instead, I would just like that when calling www.example.com/test.py, the webserver (apache or nginx) directly calls test.py. – Basj Dec 30 '19 at 13:23
  • always has to be some code which runs all time and listening on port. If you run Apache/Nginx/WSCGI then this server runs all time and listening on port. And I wouldn't expect new solution that doesn't require Python framework because frameworks make like easier, and code is better organized. Even in PHP many people prefere PHP frameworks instead of pure PHP. – furas Dec 30 '19 at 14:34

3 Answers3

1

There exists a similar mod for python, but it's not as widely used and does not seem to have been updated for a few years.

Note: A common way of doing things is using apache/nginx as a web server, and uwsgi as an application server, with the web server redirecting to the application server for non-static content urls.

blue_note
  • 27,712
  • 9
  • 72
  • 90
  • Thank you, I followed your advice and it works (see my other answer)! – Basj Oct 16 '19 at 13:33
  • I don't know why, but it's not possible to set `AddHandler mod_python .py` in a `.htaccess`, I only managed to do it globally for a ``. Would you have an idea about how to do it directly in the `.htaccess`? – Basj Oct 16 '19 at 13:37
  • @Basj: no, sorry, I just toyed with it a little a few years ago, don't know any details. – blue_note Oct 16 '19 at 13:40
  • The solution for being able to do it directly in .htaccess @blue_note is: ` AllowOverride All`... – Basj Nov 29 '19 at 08:41
1

I finally managed to do it thanks to the other answer:

  1. Do:

    apt-get install libapache2-mod-python
    
  2. Then create or open the .htaccess file in your website folder, and add

    AddHandler mod_python .py
    PythonHandler mod_python.publisher
    
  3. Then create a file test.py:

    def index(req):
        return("<html><body>Hello world</body></html>")
    
  4. Now accessing www.example.com/test.py works!


NB:

  • def index(req) is really required: using another name will make it fail.

  • I don't know why, but it's not possible to set AddHandler mod_python .py in a .htaccess, I only managed to do it globally for a <VirtualHost>. Does someone have an idea about how to do it directly in the .htaccess?

  • if mod_python is already installed but not enabled, you have to do:

    a2enmod python               
    service apache2 restart    
    

    but this is done automatically when installing libapache2-mod-python.

  • This is needed in the Apache VirtualHost's Directory: AllowOverride All, Require all granted, to allow handlers to be added directly in a .htaccess file. Without it, an alternative is to add the directives AddHandler ... directly in the VirtualHost definition.

Basj
  • 41,386
  • 99
  • 383
  • 673
  • Note: this works, but `mod_python` is often cited as non-maintained. Is there a newest solution (NB: not requiring any framework nor a constantly running script). – Basj Dec 30 '19 at 13:24
1

There is one more module apache can able to server python apart from mod_python which is mod_wsgi you may have tried it already if not this can be done like below.

First install if not already installed

sudo apt-get install libapache2-mod-wsgi -y

Create vhost

<VirtualHost *:8081>

    #ServerName www.example.com
    #ServerAlias example.com
    ServerAdmin webmaster@localhost

    DocumentRoot /var/www/html/wsgi

    <Directory /var/www/html/wsgi>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>

    WSGIScriptAlias /myapp /var/www/html/wsgi/index.py #path to file

    <Directory /var/www/html/wsgi>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>

</VirtualHost>

Create index.py

def application(environ, start_response):
    status = '200 OK'
    output = b'<h2>Hello World!</h2>'

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

    return [output]
Abhishek Gurjar
  • 7,426
  • 10
  • 37
  • 45
  • Is there a way to make mod_wsgi act like a .py handler? i.e. without of specifying `WSGIScriptAlias /myapp /var/www/html/wsgi/index.py` manually, `www.example.com/test.py` would automatically call `/var/www/html/wsgi/test.py`, `www.example.com/index.py` would automatically call `/var/www/html/wsgi/index.py`, etc. – Basj Jan 05 '20 at 15:12