How to install Python as a CGI module in Apache on Linux
May 21, 2023
Table of contents
1. How to run a Python script on a web server
2. How to set up Python as a CGI module in Apache on Debian (Ubuntu, Linux Mint, Kali Linux)
2.1 Setting up Python CGI for a single directory
2.2 Setting up Python CGI for the entire web server
3. How to set up Python as a CGI module in Apache on Arch Linux (Manjaro, BlackArch)
3.1 Setting up Python CGI for a single directory
3.2 Setting up Python CGI for the entire web server
4. Errors when configuring Python CGI
4.3 Server Error “Error 500. malformed header from script 'test.py': Bad header”
4.4 Error “This site can't be reached. localhost refused to connect”
How to run a Python script on a web server
Python supports the Common Gateway Interface (CGI), that is, programs (scripts) written in Python can interact with information servers, such as HTTP servers (Apache, for example).
The web server can run Python scripts and output the resulting data even if Python is not installed as a web server CGI module.
For example, in the following PHP script, the script receives data from a form using the POST method and then runs the Python program, passing the received data as command line arguments:
<?php echo shell_exec ('python /srv/http/test-python/script.py ' . $_POST["name"] . ' ' . $_POST["surname"] . ' '. $_POST["info"]);
After the execution of the Python script is completed, the information received from script.py will be displayed.
While there are advantages to this approach – no need to configure Python as a web server CGI module – there are some drawbacks.
If Python is not installed as a CGI module, then:
- PHP must be used to run Python scripts
- Python scripts will not have direct access to data passed by GET and POST methods.
Accordingly, configuring Python as a web server CGI module makes it possible to run scripts directly and access web server environment variables directly, including data passed by GET and POST methods.
Here's how to set up Python to Apache as a CGI for two groups of distributions:
- Debian and derivative distributions (Ubuntu, Linux Mint, Kali Linux)
- Arch Linux derivative distributions (Manjaro, BlackArch)
The step of installing Python into the operating system is skipped, since Python is preinstalled by default for most operating systems. If you don't have Python on your Linux, install it first.
There are 2 setting options:
- Python scripts are only processed by the CGI module if they are placed in a special directory on the web server (eg cgi-bin)
- Python scripts are processed by the CGI module in any webserver folder
See also: How to get data from a web page using GET and POST methods in a Python script
How to set up Python as a CGI module in Apache on Debian (Ubuntu, Linux Mint, Kali Linux)
Setting up Python CGI for a single directory
Run the command to enable the CGI module:
sudo a2enmod cgi
Restart the web server for the changes to take effect:
sudo systemctl restart apache2
Create file /usr/lib/cgi-bin/test.py:
sudo gedit /usr/lib/cgi-bin/test.py
Copy the following content to this file:
#!/usr/bin/python3 print ("Content-type: text/html") print ("") print ("") print ("<html><head>") print ("") print ("</head><body>") print ("Hello.") print ("</body></html>")
Make this file executable:
sudo chmod +x /usr/lib/cgi-bin/test.py
Open http://localhost/cgi-bin/test.py in a web browser
If everything is configured correctly, then you should see a line in the web browser
Hello.
Note: If instead of the /usr/lib/cgi-bin/ directory you want to use another folder for CGI scripts, then specify it in the /etc/apache2/conf-enabled/serve-cgi-bin.conf file.
Setting up Python CGI for the entire web server
Run the command to enable the CGI module:
sudo a2enmod cgi
Open the /etc/httpd/conf/httpd.conf file – the web server configuration file:
sudo gedit /etc/httpd/conf/httpd.conf
Find a group of lines there
<Directory /var/www/> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory>
and replace them with
<Directory /var/www/> Options Indexes FollowSymLinks ExecCGI AllowOverride None Require all granted </Directory>
ATTENTION: your set of options may be different.
Add the following line to the end of the file:
AddHandler cgi-script .cgi .py
Close the file.
Restart the web server for the changes to take effect:
sudo systemctl restart apache2
Create file /var/www/html/test.py:
sudo gedit /var/www/html/test.py
Copy the following content to this file:
#!/usr/bin/python3 print ("Content-type: text/html") print ("") print ("") print ("<html><head>") print ("") print ("</head><body>") print ("Hello.") print ("</body></html>")
Make this file executable:
sudo chmod +x /var/www/html/test.py
Open http://localhost/test.py in a web browser
If everything is configured correctly, then you should see a line in the web browser
Hello.
How to set up Python as a CGI module in Apache on Arch Linux (Manjaro, BlackArch)
Setting up Python CGI for a single directory
Create a directory /srv/http/cgi-bin/ - this is where the Python scripts will be located:
sudo mkdir /srv/http/cgi-bin/
Open the /etc/httpd/conf/httpd.conf file – the web server configuration file:
sudo gedit /etc/httpd/conf/httpd.conf
Find a group of lines:
<Directory "/srv/http/cgi-bin"> AllowOverride None Options None Require all granted </Directory>
And replace it with:
<Directory "/srv/http/cgi-bin"> AllowOverride None Options ExecCGI Require all granted </Directory>
Note: if you do not see the difference, then pay attention to the “Options” directive – the “ExecCGI” option has been added.
Find a group of lines
<IfModule mpm_prefork_module> #LoadModule cgi_module modules/mod_cgi.so </IfModule>
And replace with
<IfModule mpm_prefork_module> LoadModule cgi_module modules/mod_cgi.so </IfModule>
That is, uncomment the line.
Notice the line
ScriptAlias /cgi-bin/ "/srv/http/cgi-bin/"
It is not necessary to change it, but if you wish, you can use any other folder instead of /srv/http/cgi-bin/, you just need to create a new folder and specify it with this directive instead of /srv/http/cgi-bin/.
Close the file.
Restart the web server for the changes to take effect:
sudo systemctl restart httpd.service
Create file /srv/http/cgi-bin/test.py:
sudo gedit /srv/http/cgi-bin/test.py
Copy the following content to this file:
#!/usr/bin/python3 print ("Content-type: text/html") print ("") print ("") print ("<html><head>") print ("") print ("</head><body>") print ("Hello.") print ("</body></html>")
Make this file executable:
sudo chmod +x /srv/http/cgi-bin/test.py
Open http://localhost/cgi-bin/test.py in a web browser
If everything is configured correctly, then you should see a line in the web browser
Hello.
Setting up Python CGI for the entire web server
Open the /etc/httpd/conf/httpd.conf file – the web server configuration file:
sudo gedit /etc/httpd/conf/httpd.conf
Find a group of lines
<IfModule mpm_prefork_module> #LoadModule cgi_module modules/mod_cgi.so </IfModule>
And replace with
<IfModule mpm_prefork_module> LoadModule cgi_module modules/mod_cgi.so </IfModule>
That is, uncomment the line.
Then find the line
Options Indexes FollowSymLinks
and add “ExecCGI” to it. You should get the following line (ATTENTION: your set of options may be different):
Options Indexes FollowSymLinks ExecCGI
Now find the line:
#AddHandler cgi-script .cgi
Uncomment it, that is, remove the # symbol at the beginning of the line and add .py to the end of the line. The new line will look something like this:
AddHandler cgi-script .cgi .py
Close the file.
Restart the web server for the changes to take effect:
sudo systemctl restart httpd.service
Create file /srv/http/test.py:
sudo gedit /srv/http/test.py
Copy the following content to this file:
#!/usr/bin/python3 print ("Content-type: text/html") print ("") print ("") print ("<html><head>") print ("") print ("</head><body>") print ("Hello.") print ("</body></html>")
Make this file executable:
sudo chmod +x /srv/http/cgi-bin/test.py
Open http://localhost/test.py in a web browser
If everything is configured correctly, then you should see a line in the web browser
Hello.
Errors when configuring Python CGI
Instead of executing, the web server shows the source code of the Python script, or the file is downloaded instead of executing
This means that the CGI setup has not been done or is not complete. The reasons may be:
- webserver not restarted after making changes to config files
- you edited the wrong config file
- you have configured CGI scripts to run only in one folder, but you are trying to run the script in another
Server error “Error 500. End of script output before headers” for Python scripts only (otherwise the webserver works fine)
An example of the error that a web browser shows when trying to execute a Python script on a web server:
Server error! The server encountered an internal error and was unable to complete your request. Error message: End of script output before headers: test.py If you think this is a server error, please contact the webmaster. Error 500
The reasons for the error can be:
- Python file is not executable (no execute permission)
- Python program has a syntax error that causes the script to terminate prematurely
To check if the script has permission to run, you can use the ls utility with the -l option, after which specify the full path to the file:
ls -l /srv/http/cgi-bin/test.py
Sample output:
-rwxr-xr-x 1 root root 127 May 20 13:11 /srv/http/cgi-bin/test.py
The letters “x” mean that it has privileges to run as a program.
To check for syntax errors, run the script on the command line with the full path before it:
/srv/http/cgi-bin/test.py
Server Error “Error 500. malformed header from script 'test.py': Bad header”
An example of another error:
Server error! The server encountered an internal error and was unable to complete your request. Error message: malformed header from script 'test.py': Bad header: <html><head> If you think this is a server error, please contact the webmaster. Error 500
The key is the message “malformed header from script”, i.e. incorrect headers.
This refers to HTTP protocol headers. When Python is running as CGI, the script should start its output by sending an HTTP header followed by two blank lines.
For example, the following code will throw an error:
#!/usr/bin/python3 print ("<html><head>") print ("") print ("</head><body>") print ("Hello.") print ("</body></html>")
To avoid an error, the code should be like this:
#!/usr/bin/python3 print ("Content-type: text/html") print ("") print ("") print ("<html><head>") print ("") print ("</head><body>") print ("Hello.") print ("</body></html>")
Error “This site can't be reached. localhost refused to connect”
If, after making changes to the Apache configuration file, you begin to receive an error message:
This site can’t be reached localhost refused to connect.
It is most likely that the Apache configuration was done incorrectly, as a result of which it was not possible to restart the web server.
The error may be due to incorrect syntax.
To view the status of a web server on Debian and derivative distributions, run the command:
sudo systemctl status apache2
To view the web server status on Arch Linux and derivative distributions, run the command:
sudo systemctl status httpd.service
Useful links:
- https://docs.python.org/3/library/cgi.html
- https://www.tutorialspoint.com/python/python_cgi_programming.htm
Related articles:
- How to set up Python as a CGI module in Apache on Debian (Ubuntu, Linux Mint) (92.1%)
- How to set up Python as a CGI module in Apache on Arch Linux (Manjaro, BlackArch) (85.7%)
- How to get data from a web page using GET and POST methods in a Python script (77.8%)
- Error “Cannot load modules/libphp7.so” (SOLVED) (73%)
- Chromium will no longer sync passwords - what should Linux users do? (72.3%)
- How to find out which package contains a file (RANDOM - 53.9%)