Running a Python web application without ...

Running a Python web application without frameworks on Debian 11 and Apache HTTP Server

May 26, 2023

If you aim to build a web application in Python without frameworks, you're in the right place. This guide presents a practical, step-by-step recipe that will walk you through the process of creating CGI web applications on Apache for Debian.

This guide explains how to run a Python CGI application over an Apache HTTP Server for Debian GNU/Linux and derived distributions.

To run a Python CGI application over an Apache HTTP Server, follow these steps:

1. Preparing the directory structure

The most straightforward organization of a Python CGI application could have the following structure:

myproject/             # The project folder
├── logs               # The logs directory
└── root               # The web directory
    └──   # The script files

This guide makes the myproject folder in the /srv directory. To create the directory structure, follow the next instructions as a root user.

1. Make the directory structure:

# mkdir -p /srv/myproject/{root,logs}

2. Set up 755 permissions to the web directory:

# chmod -R 755 /srv/myproject/root/

3. Change the root directory owner to your own user (this step allows you to code inside the root folder as a non-root user):

# chown yourusername: /srv/myproject/root/

Remember to change yourusername to the username you want to use for building your software (for example, eugenia.) You can now work on the myproject/root folder as a non-root user.

2. Writing a CGI script

The first thing to bear in mind is that a Python CGI script is a Python script that sends HTTP headers before sending any other body message. This is not a special Python requirement but a CGI one derived from the HTTP protocol. For this protocol, an HTTP message is a two-part data packet, where the first part is the HTTP header section and the second part is the body. Between both parts, there is a blank line. Since a Python CGI script is a script, it needs the proper hashbang and execution permissions.

To write a Python CGI script, follow the next instructions as a non-root user.

1) Make an empty file in the root folder of your application:

$ touch /srv/myproject/root/

2) Copy and paste the following lines inside the file and save it:

#!/usr/bin/env python3

# Header mandatory field
print("Content-Type: text/html; charset=utf-8")  
# Blank line between the HTTP header and the HTTP body
# Body message
print("Hello world!")  

3) Give execution permissions to the file:

$ chmod +x /srv/myproject/root/

3. Installing the Apache HTTP server

The Apache HTTP Server is the web server software. To install it on a Debian-based system, execute the following command as a root user:

# apt install apache2

If you need to start, stop, restart, or reload the Apache HTTP service, you can do it through systemctl by executing the following command as a root user:

# systemctl <command> apache2

Where <command> can be startstoprestart or reload.

4. Configuring the Apache HTTP server

We must give the Apache HTTP Server access to the application’s root directory by editing the configuration file. On Debian-based systems, this file is generally in:


As a root user, follow the next instructions to give the Apache HTTP Server access to the application root directory.

1) Open the configuration file and grant access to the application root directory by adding these lines:

<Directory /srv/myproject/root/>
    # This line prevents file listing
    Options -Indexes
    # This line concedes Apache access
    Require all granted

2) Save and close the file, then restart the Apache HTTP Server:

# systemctl restart apache2

5. Choosing and enabling the CGI module

The Apache HTTP Server can work with a multiprocessing module (MPM). For Linux systems, are three MPMs available: MPM worker, MPM event (a variant of worker), and MPM prefork (a non-threading MPM).

When the Apache HTTP Server works with an MPM under Unix, Apache recommends using the mod_cgid module instead of mod_cgi. The documentation explains this by arguing that in some Unix systems, forking processes require replicating the parent threads. As this forking procedure is expensive, the cgid module uses an external daemon to do it and achieve better performance. The MPM exception to work with the cgid module is MPM prefork because it is a non-threading MPM.

The main problem with the cgid module is the debugging process because it requires an extra directive in the virtual host file to log errors in a separate file with write permissions. The cgid module does not report all the standard errors produced by Python.

If you need to use an MPM such as worker or event, a suitable alternative is to reserve the cgid module for a production stage and, for comfortable debugging, to use mod_cgi on a local machine.

In the following steps, we pick to work with MPM prefork and the cgi module.

For enabling MPM prefork and mod_cgi on Debian-based systems, execute the following commands as a root user:

# a2dismod mpm_event
# a2dismod mpm_worker
# a2enmod mpm_prefork
# a2enmod cgi
# systemctl restart apache2

The a2dismod command is executed to turn off unnecessary modules in the case that they are enabled.

6. Setting up the server name

If you are running the CGI script on a local machine, it is sufficient to add—as a root user—a new host on the /etc/hosts file pointing to the local IP:    mylocalhost.local

To run the CGI script on a public server, you have to add a new A record (or AAAA if you are working on an IPv6) in your DNS zone file.

7. Configuring the virtual host

virtual host is the result of implementing a technique that allows more than one website to run on the same machine. The Apache HTTP Server supports IP-based and name-based virtual hosts through the <VirtualHost> directive. This directive can be in a common or single configuration file.

This guide shows how to use a name-based virtual host in a single file.

You have to allow the CGI execution and set a handler to run CGI scripts by adding two lines to the directory directive:

      Options +ExecCGI
      SetHandler cgi-script

To create the virtual host file, follow these instructions as a root user.

1) Create an empty virtual host file (we name it mylocalhost.conf):

# touch /etc/apache2/sites-available/mylocalhost.conf

2) Open the virtual host file and add the following lines:

<VirtualHost *:80>
    ServerName mylocalhost.local
    DocumentRoot "/srv/myproject/root/"
    ErrorLog "/srv/myproject/logs/error.log"
    CustomLog "/srv/myproject/logs/custom.log" combined

    <Directory "/srv/myproject/root/">
        Options +ExecCGI
        SetHandler cgi-script

Note that you must change mylocalhost.local to your server name.

3) Enable the virtual host:

# a2ensite mylocalhost.conf

4) Restart the Apache HTTP server:

# systemctl restart apache2

8. Running and debugging the Python CGI script

To run the previously created script, go to http://YOURSERVERNAME.TLD/ (remember to change YOURSERVERNAME.TLD to your server name). If everything runs as expected, you should see the “Hello World!” screen. If you get an 'Internal Server Error,' you should read the error log file to identify the error, understand why it occurred, and locate where it happened. You can do it by executing the following command as a non-root user:

$ tail -f /srv/myproject/logs/error.log

Enjoy this post?

Buy Eugenia Bahit a coffee

1 comment

More from Eugenia Bahit