Once you have built a LAMP server on Ubuntu, the next important step is ensuring that every component on the server is optimized and fine-tuned. This will allow your website or web application to run much much quicker, leading to better overall stability.

Previously, we built a LAMP server that consisted of either MySQL or PostgreSQL (and so both are covered here), and Python instead of PHP.

Fine-tuning your LAMP server


Apache is our web server of choice because it is stable, well-supported, and completely open source. Out of the box, Apache works great for running websites and web applications, but could benefit from removing some unnecessary modules and fine-tuning.

Disable Unnecessary Modules

Apache is designed in a modular fashion so that web servers can be customized for particular needs. Popular modules add the ability to rewrite URLs, provide SSL encryption, and more. Apache comes with many of these modules enabled by default, however, which can mean unnecessary overhead and bloat on your server.

In Ubuntu, you can see a list of enabled modules and a list of all available modules in the /etc/apache2/mods-enabled and /etc/apache2/mods-available directories, respectively. To list all modules or just enabled modules, you can use the following command:

ls /etc/apache2/mods-enabled


Note that the modules enabled in the example and the modules you have enabled might look different.

Apache modules can be very finicky, as they often have cross-dependencies, and there is no silver bullet for which modules to disable — you must make that decision on a case-by-case basis. For the purposes of our project, which consists of Apache, MySQL or PostgreSQL, and Python, here are the modules that you can consider disabling:

  • PHP, Perl – Since we are using Python for our web application
  • SSL – If you do not require your server to make secure HTTP connections
  • auth and authz – Only necessary if you are having Apache do authentication work
  • alias – Used for manipulation of URLs, but we’ll be using mod_rewrite instead
  • autoindex – When no index.html is present, displays directory listing
  • cgi – Enables use of CGI scripts
  • negotiation – Matches document with client responsibilities
  • filter – Custom-filters requests
  • version – Allows testing with multiple versions

The syntax to disable a given module is:

sudo a2dismod ssl

Disable Apache2 Module

If you are interested in enabling a module, you can use:

sudo a2enmod ssl

Note that after you enable or disable Apache modules, you will need to run sudo service apache2 restart.


Perhaps the most important part of optimizing an Apache server is a proper configuration. If you have a misconfigured Apache server, your website or web application will start to choke under the pressure of a large number of HTTP requests, which will, in turn, begin bringing your entire server down. This happens because every HTTP request to your website or web applications requires RAM, and once your server runs out of RAM, it starts killing off processes that are using the most. This can happen, regardless of your configuration, if you suddenly get hundreds of thousands of HTTP requests every day to your server. But at the very least, we can help mitigate the problem.

To start optimizing our configuration, we want to open up our Apache configuration file in the terminal, using nano, a terminal application that allows you to easily edit files:

nano /etc/apache2/apache2.conf

We’ll now navigate to the “prefork MPM” section, which you can search for by using CMD + W in nano. You should see something like this:

# prefork MPM
# StartServers: number of server processes to start
# MinSpareServers: minimum number of server processes which are kept spare
# MaxSpareServers: maximum number of server processes which are kept spare
# MaxClients: maximum number of server processes allowed to start
# MaxRequestsPerChild: maximum number of requests a server process serves

<IfModule mpm_prefork_module>  
    StartServers 5
    MinSpareServers 5  
    MaxSpareServers 10  
    MaxClients 256  
    MaxRequestsPerChild 10000

The code above is the configuration for the prefork module in Apache. This module is the most common method for Apache to serve HTTP requests. What we need to calculate now is the value we should have for MaxClients.

To do this, we use the following formula: (Total Memory – Database System Memory) / Size Per Apache process.

In this equation, you will be subtracting total memory either from MySQL memory or from PostgreSQL memory.

To find out these values, let’s run the following commands (thank you to Woktron for this advice):

free -mps aux | grep 'mysql' | awk '{print $6}'ps aux | grep 'postgresql' | awk '{print $6}'ps aux | grep 'httpd' | awk '{print $6}'

Your output should look similar to:

So for my personal server — where I have 1992 MB of available memory, MySQL (or PostgreSQL) is taking up 21 MB, and the average Apache process is 22 MB — the equation would be MaxClients = (1992 - 21) / 22, which gives a value of 90 for MaxClients.

Be sure to restart Apache after making these changes:

sudo service apache2 restart

Also note that if you are interested in the other configuration values in this file (StartServers, MinSpareServers, MaxSpareServers, MaxRequestsPerChild), Graham Dumpleton has a great presentation that explains the differences in each value and how changing them can affect your server.


Unlike a lot of tools like Apache or Python, database systems are something that need to be regularly maintained. This is because your database size will likely change over time, as will the number of people querying it. However, we will be using a tool called MySQLTuner, which makes this maintenance easy.

You can install MySQLTuner using the following command:

sudo apt-get install mysqltuner

And you can now run it by typing:


The script will ask for your MySQL username and password, after which you should get an output that looks similar to this:

MySQLTuner Output

The script will give you a list of variables to adjust, which can be changed in /etc/mysql/my.conf.

Be sure to follow MySQLTuner’s recommendations, though, before making changes:

  • When making adjustments, make tmp_table_size/max_heap_table_size equal
  • Increase table_cache gradually to avoid file descriptor limits

After making changes to the configuration, you will also need to restart MySQL:

sudo service mysql restart


Similar to MySQL, for PostgreSQL we will be using a tool called PGTune to help with tuning our configuration. However, unlike MySQLTuner, PGTune is an online tool that allows you to input your hardware settings and primary database use, after which it spits out configuration settings that you can just copy and paste.

Here’s an example of what mine looked like:


You can now take those configuration settings and add/replace them in the /etc/postgresql/[version]/main/postgresql.conf file


In regards to Python, there isn’t terribly much that you can do on the server side of things to optimize your Python application much further. However, if you have written or are planning on writing a Python application, I recommend reading the official Python Performance Tips page to help in writing a performant application.

The Finish Line

With that, you should now have a fine-tuned LAMP server that you can deploy Python applications on, but which also isn’t hogging unnecessary resources or choking under the pressure of many HTTP requests.