We optimize VPS for $ 5 (512MB RAM / 1 CPU) so that the wordpress site can withstand a load of 42,735,587 hits per day

When you purchase a VPS server with 256MB or 512MB of RAM on board and only part of the processor power, using the default settings for services such as MySQL / PHP / Apache is a very bad idea. Currently, I have launched 3 sites on the cheapest tariff plan with 512MB RAM / 1 CPU. Not completely sure, but the attendance is about 5-10 thousand visitors per day. Next, I want to share instructions on how to optimize LAMP using only 512 MB and without going to swap. Typically, with this setting, 256 - 378Mb of memory is used and everything works pretty quickly.

We determine the available memory and swap activity.

Before starting the optimization, let's take a look at the amount of memory used. To do this, run the following command:

$ free -m

For. to see a list of running processes and sort them by memory usage, you need to run this command:

$ ps -eo pmem,pcpu,rss,vsize,args | sort -k 1 -r | less

We configure the LAMP server to consume a small amount of RAM. Stop, disable unnecessary services

The first and obvious question to ask is “what services do I not need to use?”. Recently, I discovered a very convenient utility for managing services. It is called " sysv-rc-conf " and manages services using pseudo-graphics and checkboxes. Looks like this:

Here is a list of services that I changed.

  • The Postfix . This service allows you to send and receive email messages for a domain. For these purposes, I use Google Apps to send mail and mailchimp to news subscribers. So I stopped and turned off this service.
  • Bind9 . It is needed to manage the DNS records of your domain. It can be disabled, since all DNS records are stored on the host.
  • SSHD . There are other implementations that use much less memory, but they do not support sftp, so I left this service unchanged.

Do not start the X-server, turn off all unnecessary services and configure Apache, MySQL, PHP with only the basic necessary functionality.


Apache's biggest problem is the amount of RAM it uses. I will consider the following ways to speed up work and reduce RAM consumption:

  • Handle fewer concurrent requests
  • Less loading of modules (disable unused);
  • Less logging.

Configure Apache to use only the fewest running child processes

Prefork is where the real magic happens. This is where we tell Apache to generate many processes. By default, a large amount is allocated, which leads to the consumption of server RAM. Make sure apache2.conf is not configured to run too many servers or has many spare ones. Below is an example:

    StartServers          1
    MinSpareServers       1
    MaxSpareServers       3
    MaxClients           10
    MaxRequestsPerChild 3000

    StartServers          1
    MinSpareThreads       5
    MaxSpareThreads      15 
    ThreadLimit          25
    ThreadsPerChild       5
    MaxClients           25
    MaxRequestsPerChild 200

Also, be sure to adjust the " KeepAliveTimeout " setting to 10 or 15. In my opinion, 15 seconds is too much than a small page needs to view and shorter than it takes to take a long time to view the page.

Download only the most necessary modules

The default Apache web server loads too many unnecessary modules. You can check which modules are installed and enabled by the following command:

# apache2ctl -M

Below is a list of modules that are required for Wordpress to work.

LoadModule dir_module modules/mod_dir.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule alias_module modules/mod_alias.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule rewrite_module modules/mod_rewrite.so

You need to comment out the remaining modules to save memory. Or you can enable / disable modules through the command line. To enable, use the command:

# a2enmod module_name

To disable:

# a2dismod module_name

After the manipulations, you must definitely restart the Apache web server:

# service apache2 restart

Reduce logging

If you want to maximize performance, you definitely need to limit logging. On my server I set the level to “error”. Also, if you do not need detailed statistics, you can disable User-Agent or the http-referer logging.

# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a 
# container, error messages relating to that virtual host will be
# logged here.  If you *do* define an error logfile for a 
# container, that host's errors will be logged there and not here.
ErrorLog ${APACHE_LOG_DIR}/error.log
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel error

I am satisfied with such settings, but you decide.

MySQL server optimization

Tuning MySQL to use a small amount of RAM is quite simple.
Next, we will consider the following types of MySQL settings:

  • Things we can turn off;
  • Optimization of MySQL server parameters;
  • Third-party MySQL configuration customization tools.

To optimize MySQL, we need to edit the /etc/mysql/my.cnf file .

Things we need to turn off

Mysql provides several table storage engines. Two of them are the most popular - they are InnoDB and MyISAM . The main differences between them:
  • MyISAM offers table-level locks, which means that when information is written to the table, the entire table is locked and if at that moment there are more records that must be executed simultaneously in the same table, then they will have to wait until the first record is added successfully ;
  • InnoDB , on the other hand, offers row-level locks, which means that when a write to a string occurs, only that single row is locked; the rest are available for recording.

Table-level lock problems are only noticeable on very busy servers. For regular websites, MyISAM shows the best performance on cheap servers.

If you decide to use MyISAM tables, then you need to add the following lines to the my.cnf configuration file:


If you have only MyISAM tables, you can disable the InnoDB engine, thereby saving RAM by adding only one line to my.cnf:


If you used InnoDB in the past, then below I will provide you with a script that will automatically convert all InnoDB tables to MyISAM.

for db in `echo show databases | $MYSQLCMD | grep -v Database`; do
        for table in `echo show tables | $MYSQLCMD $db | grep -v Tables_in_`; do
                TABLE_TYPE=`echo show create table $table | $MYSQLCMD $db | sed -e's/.*ENGINE=\([[:alnum:]\]\+\)[[:space:]].*/\1/'|grep -v 'Create Table'`
                if [ $TABLE_TYPE = "InnoDB" ] ; then
                        mysqldump $db $table > $db.$table.sql
                        echo "ALTER TABLE $table ENGINE = MyISAM" | $MYSQLCMD $db

We optimize the parameters of the MySQL server

Below are a few parameters that can be adjusted to speed up the MySQL server.

Key buffer size

This is one of the most important parameters affecting RAM consumption and performance that needs to be optimized. MySQL tries to put everything that is indexed in key buffer, so this option brings tremendous performance. The SQL query will be submitted directly from the RAM. I can’t say what size you should set for key buffer, because only you know how much RAM you have available.

The query cache

If you make the same queries twice in a row, then the result is placed in the query cache, so mysql will not have to do the query again. If you intend to improve performance, this option can be of great benefit, but memory consumption will increase. Therefore, you need to set this parameter not too huge, but not too small, that is, as much as your website needs.

The following are three variables that affect how your query cache works:


Maximum Number of Connections

This is an optional parameter. If you have already limited the number of apache processes, then everything is already fine. If not, and you need to process thousands of users at the same time, you need to increase the value of this parameter.

The table cache

Each time you access a table, MySQL loads the table reference as one entry in the table cache. This is done for each parallel access to the table, it is really important for performance, not much for memory usage. You can constantly increase the table cache, but then you will run into the limit on the number of open files in your operating system, so keep that in mind. If the table cache is too small, then mysql will puke on you, but you do not want this.

Below is the correct my.cnf, which I optimized on my VPS with the lowest tariff plan.
My my.cnf

     port            = 3306
     socket          = /var/lib/mysql/mysql.sock
     key_buffer = 16K
     max_allowed_packet = 1M
     table_cache = 4
     sort_buffer_size = 64K
     read_buffer_size = 256K
     read_rnd_buffer_size = 256K
     net_buffer_length = 2K
     thread_stack = 64K
     # For low memory, InnoDB should not be used so keep skip-innodb uncommented unless required
     # Uncomment the following if you are using InnoDB tables
     #innodb_data_home_dir = /var/lib/mysql/
     #innodb_data_file_path = ibdata1:10M:autoextend
     #innodb_log_group_home_dir = /var/lib/mysql/
     #innodb_log_arch_dir = /var/lib/mysql/
     # You can set .._buffer_pool_size up to 50 - 80 %
     # of RAM but beware of setting memory usage too high
     #innodb_buffer_pool_size = 16M
     #innodb_additional_mem_pool_size = 2M
     # Set .._log_file_size to 25 % of buffer pool size
     #innodb_log_file_size = 5M
     #innodb_log_buffer_size = 8M
     #innodb_flush_log_at_trx_commit = 1
     #innodb_lock_wait_timeout = 50
     max_allowed_packet = 16M
     # Remove the next comment character if you are not familiar with SQL
     key_buffer = 8M
     sort_buffer_size = 8M
     key_buffer = 8M
     sort_buffer_size = 8M

Third-party MySQL configuration wizards

I found Percona, which provides free MySQL tuning and helps you choose the best MySQL server features to achieve the best performance, as well as save time, avoid the difficult moments and risks that may arise when you configure my.cnf yourself.

MySQL server monitoring

MySQL stores statistics that help determine the best values ​​to use. In addition, there are two convenient utilities that you can use to read these statistics and display them in an understandable format: tuning-primer.sh and mysqltuner.pl .
These scripts will allow you to monitor your MySQL server, and then provide a hint about the parameters that need to be configured on your server.

PHP optimization and caching

PHP does not use memory very intensively, so I don’t think that you need to worry much about the memory consumption of these processes, if your application does not need it, but even if optimization is necessary, there will be no significant reduction in memory consumption. But I researched and then found several settings for PHP configurations that reduce web server memory consumption.

; Limit the memory to 40M should be fine for barebones Wordpress
memory_limit = 48M

Alternative PHP Cache

Install PHP Cache, for example, such as Alternative PHP Cache. PHP cache will store compiled PHP scripts in such a way that they will be reused without compilation and, accordingly, will not create a load:

# pecl install apc

Below is my configured php.ini file.
My php.ini

;32M per WordPress install
;Relative to the number of cached files (you may need to watch your stats for a day or two to find out a good number)
;Relative to the size of WordPress
;The number of seconds a cache entry is allowed to idle in a slot before APC dumps the cache
;Setting this to 0 will give you the best performance, as APC will
;not have to check the IO for changes. However, you must clear 
;the APC cache to recompile already cached files. If you are still
;developing, updating your site daily in WP-ADMIN, and running W3TC
;set this to 1
;This MUST be 0, WP can have errors otherwise!
;Only set to 1 while debugging
;Allow 2 seconds after a file is created before it is cached to prevent users from seeing half-written/weird pages
;Leave at 2M or lower. WordPress does't have any file sizes close to 2M
;Ignore files
apc.filters = "/var/www/apc.php"
apc.rfc1867_prefix =upload_

Static cache

Another thing that might be a good idea for a blog on a small server is to put it in front of a static HTTP cache, like Varnish. Which can really increase your scalability. Varnish configuration is a separate large article that requires a separate topic.


I put open the configuration of my web server in order to prove that you can achieve high performance even from the cheapest VPS container with 512MB RAM and 1Ghz CPU. I use Ubuntu 12.04 LTS, LAMP, Varnish, APC Cache to host 3 websites made on Wordpress (not multisite) with a traffic of 10k per day. Let's take a look at the test results from Blitz.io:

As you can see, 0.23% of users get Connection Timeout, when my website has 42,735,587 hits per day (WOW), something else can be optimized, but I enjoy working my web server. If you are tired of this manual or do not want to do it by hand, you can use services such as PuPHPet or Vagrant.

Also popular now: