Tutorials

Bootstraping WordPress/Nginx/PHP/MySQL on a Cheap VPS with lowendscript

One constantly posted question on LowEndBox and LowEndTalk is — how to get the same setup as LowEndBox, a WordPress site that runs on cheap VPS with 80MB of memory? Instead of doing a step-by-step explanation (damn I hate writing long blog posts), I decided to wrap it into a bash script that does it all.

NginxPHP
WordPressMySQL

It is based on my previous script here, and it has been tested on both Debian 5 “Lenny” and Ubuntu 10.04 “Lucid Lynx”. Sorry no other distributions are supported. It is currently hosted at github so feel free to branch it and tune it to your heart’s desire.

Usage

Here is a quick step by step on how to set up a WordPress blog running on Nginx, PHP/FastCGI and MySQL on a low end box. Let’s assume that you are going to set up a blog on hostname “blog.example.com“.

  1. Go and buy a cheap VPS. Yes, you know where to find cheap virtual servers under $7/month, don’t you? 🙂 I am using my 6 pound/year RackVM VPS with 128MB memory to test this script, and the performance turns out to be quite good. YMMV.

    Make sure it is either a Debian or a Ubuntu distro though.

  2. After gaining root access to your VPS,
    # wget --no-check-certificate https://github.com/lowendbox/lowendscript/raw/master/setup-debian.sh
    ...
    # bash setup-debian.sh system
    ...
    # bash setup-debian.sh exim4
    ...
    # bash setup-debian.sh nginx
    ...
    # bash setup-debian.sh mysql
    ...
    # bash setup-debian.sh php
    ...
    # bash setup-debian.sh wordpress blog.example.com
    ...
    
  3. Now altering your DNS entry to point blog.example.com to your new VPS (or alter your local /etc/hosts entry). Navigate to it from your browser, and you should be presented with WordPress set up page. Fill in your blog’s name, admin’s password and contact email, and your new WordPress is online!

    Just repeat the last step (running bash setup-debian.sh wordpress <hostname>) to set up more blogs on the same box.

That’s it!

Software Stack

It’s pretty similar to my own stack that runs LowEndBox.com.

  • dropbear to replace openssh. Invoked from xinetd.
  • inetutils-syslogd to replace rsyslog.
  • exim4 to replace sendmail (if installed). Re-configured to allow Internet delivery.
  • cron
  • nginx
  • mysql. Re-configured to remove innodb support, remove query cache and reduce key buffer size.
  • php with built-in FastCGI interface. Running only 1 child process and respawn after 5,000 requests.

The lowendscript is also

  • Removing some commonly bundled applications that should not be there in the first place for a minimal distro (apache2, sendmail, bind9, samba, nscd, etc).
  • MySQL root is given a new password (which can be found in ~root/.my.cnf)
  • Installing each WordPress site under /var/www/<hostname>. It will create appropriate database, users and password for the site.

I have to say that it is still “work in progress”, but if you want to figure out the internals please check the source code of that bash script.

Memory Usage

I am testing the same script on the following 3 systems:

  • Ubuntu 10.04 64bit (RackVM)
  • Debian 5 64bit (RackVM)
  • Debian 5 32bit (VPSGuy)

They are all showing different memory usage. I am taking the snapshot of memory usage AFTER 10 page loads on the WordPress blog that has been created to ensure PHP process is fully loaded.

Ubuntu 10.04 64bit

root@ubuntu64:~# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.5  23300  1536 ?        Ss   06:58   0:00 init
root     10124  0.0  0.5  23576  1496 ?        Ss   07:34   0:00 dropbear -i
root     15742  0.0  0.7  17880  1944 pts/0    Ss   07:35   0:00 -bash
root     15754  0.0  0.4  14960  1084 pts/0    R+   07:35   0:00 ps aux
root     24290  0.0  0.3  12508   788 ?        S    07:22   0:00 /usr/sbin/syslo
root     24524  0.0  0.3  21064  1004 ?        Ss   07:22   0:00 cron
root     25689  0.0  0.3  19512   972 ?        Ss   07:22   0:00 /usr/sbin/xinet
mysql    26346  0.0  4.2  61812 11248 ?        Ssl  07:23   0:00 /usr/sbin/mysql
www-data 27920  0.0  2.6  87768  7048 ?        Ss   07:23   0:00 /usr/bin/php-cg
www-data 27922  0.5 15.0 122460 39432 ?        S    07:23   0:04 /usr/bin/php-cg
103      30162  0.0  0.3  44356  1000 ?        Ss   07:24   0:00 /usr/sbin/exim4
root     30267  0.0  0.3  28104   932 ?        Ss   07:24   0:00 nginx: master p
www-data 30268  0.0  0.8  28744  2196 ?        S    07:24   0:00 nginx: worker p

root@ubuntu64:~# free
             total       used       free     shared    buffers     cached
Mem:        262144     100500     161644          0          0          0
-/+ buffers/cache:     100500     161644
Swap:            0          0          0

Memory Usage: 98.1MB

Debian 5 64bit

debian64:~# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.2  10304   740 ?        Ss   12:22   0:00 init [2]
106       1414  0.0  0.3  42708  1004 ?        Ss   12:26   0:00 /usr/sbin/exim4
www-data  1655  0.0  2.5  72028  6560 ?        Ss   12:26   0:00 /usr/bin/php-cg
www-data  1657  0.9 11.7  98500 30928 ?        S    12:26   0:03 /usr/bin/php-cg
www-data  3126  0.0  0.7  28380  1912 ?        S    12:29   0:00 nginx: worker p
root      7668  0.1  0.5  23340  1528 ?        Rs   12:31   0:00 dropbear -i
root      7831  0.0  0.6  17472  1716 pts/0    Ss   12:32   0:00 -bash
root      7836  0.0  0.3  14720   980 pts/0    R+   12:32   0:00 ps aux
root     20169  0.0  0.3  18540   936 ?        Ss   12:22   0:00 /usr/sbin/cron
root     24462  0.0  0.2  12236   732 ?        S    12:25   0:00 /usr/sbin/syslo
root     25637  0.0  0.3  19256   952 ?        Ss   12:25   0:00 /usr/sbin/xinet
root     25694  0.0  0.5  28380  1552 ?        Ss   12:25   0:00 nginx: master p
root     32427  0.0  0.2   3872   588 ?        S    12:26   0:00 /bin/sh /usr/bi
mysql    32466  0.0  3.0  50420  8124 ?        Sl   12:26   0:00 /usr/sbin/mysql
root     32468  0.0  0.2   3772   592 ?        S    12:26   0:00 logger -p daemo

debian64:~# free
             total       used       free     shared    buffers     cached
Mem:        262144      61008     201136          0          0          0
-/+ buffers/cache:      61008     201136
Swap:            0          0          0

Memory Usage: 59.6MB

Debian 5 32bit

debian32:~# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1   1980   688 ?        Ss   23:34   0:00 init [2]
root     14064  0.0  0.1   1704   512 ?        S    23:52   0:00 /bin/sh /usr/bi
mysql    14119  0.0  1.7  20056  6968 ?        Sl   23:52   0:00 /usr/sbin/mysql
root     14120  0.0  0.1   1628   536 ?        S    23:52   0:00 logger -p daemo
www-data 15968  0.0  1.2  16352  4996 ?        Ss   23:53   0:00 /usr/bin/php-cg
www-data 15971  0.5  4.7  29436 18576 ?        S    23:53   0:01 /usr/bin/php-cg
root     16040  0.0  0.3   2700  1464 ?        Rs   23:53   0:00 dropbear -i
root     16119  0.0  0.1   1880   684 ?        S    23:44   0:00 /usr/sbin/syslo
root     16133  0.0  0.3   2780  1536 pts/0    Ss   23:54   0:00 -bash
root     17728  0.0  0.2   2352   896 ?        Ss   23:45   0:00 /usr/sbin/xinet
www-data 17758  0.0  0.3   5004  1488 ?        S    23:54   0:00 nginx: worker p
root     27834  0.0  0.3   4548  1236 ?        Ss   23:47   0:00 nginx: master p
root     28146  0.0  0.2   2296   896 pts/0    R+   23:57   0:00 ps aux
102      32065  0.0  0.2   6104   900 ?        Ss   23:49   0:00 /usr/sbin/exim4

debian32:~# free
             total       used       free     shared    buffers     cached
Mem:        262144      44272     217872          0          0          0
-/+ buffers/cache:      44272     217872
Swap:            0          0          0

Memory Usage: 43.2MB

So to put that in summary form

  • Ubuntu 10.04 uses significantly more memory than Debian 5 (PHP5.3/MySQL5.1 vs. PHP5.2/MySQL5.0). So pick your distro wisely and maybe you don’t need the latest and greatest if your application does not need it.
  • 32bit also uses quite a bit less than 64bit, running exactly the same version of stack. That pretty much confirms what I posted before.

And hopefully the above script is useful for your next WordPress splog farm 😛

490 Comments

  1. LEA's avatar
    LowEndAdmin Author

    @Rolando — no it does not default to your blog. You can add “listen 80” under “server” in the configuration file for that virtual host and Nginx will pick that up as the default virtual host.

    Otherwise you can test by adding the IP address to your local /etc/hosts (or c:\windows\system32\drivers\etc\hosts if you are using Windoze).

    @Minh — I still don’t believe there’s a cheap cure for DDoS unfortunately. You might need to buy bigger machine.

    @AddictingGames88 — why do you need php5-fpm? Dynamic spawning of new FastCGI processes?

  2. KLIKLI's avatar
    KLIKLI

    @LEA
    Maybe Windows?

  3. LEA's avatar
    LowEndAdmin Author

    Err. That post makes no sense. PHP-FPM uses exactly the same core as PHP-FastCGI, and I can’t see how you can get better performance on standard PHP function calls. It has a much better FastCGI process management though — useful if you want “adaptive process spawning” similar to mod_fcgi in Apache.

  4. AddictingGames88's avatar
    AddictingGames88

    @Eric : How to solve FTP problem since

    /usr/sbin/setsebool -P httpd_can_network_connect=1
    -bash: /usr/sbin/setsebool: No such file or directory

  5. Nizar's avatar
    Nizar

    Hi, i’m a newbie on this, i tried to upload file on wordpress and can’t because:
    Unable to create directory /var/www/mydomain.com/wp-content/uploads/2010/09. Is its parent directory writable by the server?

    I know if in the apache we can use suPhp, how to fix this in nginx? it’s risky if i make the directory writeable.
    I also can’t using theme editor on wordpress and update plugins automatically
    Thanks

  6. Nizar's avatar
    Nizar

    @AddictingGames88
    Thanks, i got it.

  7. AddictingGames88's avatar
    AddictingGames88

    Need help on the following questions
    1)How to add new user and disable root for DropBear?
    2)If we will to install second WordPress, do we use a new ip address or the same ip as the first WordPress installation?
    Hope someone can share the answer

  8. Erawan Arif Nugroho's avatar
    Erawan Arif Nugroho

    @AddictingGames88

    1. I don’t try it yet
    2. If you can set the DNS for each subdomains, then you can easily install the second wordpress at the same IP

  9. AddictingGames88's avatar
    AddictingGames88

    @Erawan Arif Nugroho,

    2. I actually mean installing a second WordPress with a new domain name. Do I dns the new domain name to the same IP Address?

  10. Erawan Arif Nugroho's avatar
    Erawan Arif Nugroho

    @AddictingGames88

    Yes 🙂

    Previously, I have 3 domain names, and I am hosting it in one VPS (with one IP)
    Because the nginx will automatically maps the DNS requests to the directory in /var/www/domainname.com

  11. Jackk's avatar
    Jackk

    Hello,

    Is it possible to install and configure GD?

    Jack.

    • LEA's avatar
      LowEndAdmin Author

      Err. apt-get install php5-gd and then restart the PHP FastCGI processes?

  12. Denny's avatar
    Denny

    Thanks for the handy script! I have got two questions here:

    1. Everything is running OK after the installation. However, after I reboot my VPS, it seems that neither mysql nor php is running:

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
        1 root      18   0  2464 1312 1108 S  0.0  0.5   0:00.16 init
    15837 root      16   0  8272 2724 2160 S  0.0  1.0   0:00.07 sshd
    32456 root      25   0  4764  692  252 S  0.0  0.3   0:00.00 nginx
    32458 www-data  15   0  4916 1476  832 S  0.0  0.6   0:00.00 nginx
    32463 root      18   0  5468  908  504 S  0.0  0.3   0:00.00 sshd
    

    2. When I set up WordPress, I used “www.mydomain.com” as the server name. Is there any way to config both “mydomain.com” and “www.mydomain.com” to my blog?

    Thanks

    • LEA's avatar
      LowEndAdmin Author

      1. They should be automatically restarted. Check whether php-cgi and mysql are in /etc/rc2.d

      2. You can add a new file called /etc/nginx/sites-enabled/mydomain.com.conf

      server {
          server_name mydomain.com;
          rewrite ^(.*)$ $scheme://www.mydomain.com$1 permanent;
      }
      
  13. Nickolai Leschov's avatar
    Nickolai Leschov

    LowEndAdmin, thanks again for your script and help.

    It is actually true, I can access my site with SFTP without any extra FTP software. I use FireFTP add-on for Firefox, which supports SFTP too! On Windows, I was used to FAR Manager with WinSCP plug-in.

    So I managed to make my VPS into a file host with nginx: I ordered a 256MB Xen VPS from 2HOST for $4.94 monthly (SATA variety, originally $5.49, code LEB10TB for 10% discount), did “” did the script up to nginx and uploaded my files. Alas, download speed from my server is around 100 kilobytes/s. If we download from two different computers, it gives us around 100 kilobytes/s each. I tried tweaking around with nginx configuration, but nothing helps.

    When I ssh to server and download files with wget it goes 100 kilobytes/s from some locations. From some it is over megabyte/s.

    Is the hosting provider throttling me? Can I do anything? Or maybe it’s just misconfiguration on my part?

    My site: http://178.18.17.199/
    file: http://178.18.17.199/firefox-4.0b6.tar.bz2

    • LEA's avatar
      LowEndAdmin Author

      You might want to study a bit on Nginx configuration — this script is intended for those who know what they are doing to save time 🙂

      You can use

      server {
          server_name my-new-website.com;
          listen ipaddress:80;
          ...
      }
      

      to have the site on a different IP address.

      • AddictingGames88's avatar
        AddictingGames88

        Thanks for your reply. I will do a bit of study on Nginx configuration. I need different IP as I am moving existing live sites to new server without bring down the sites.

  14. Ron's avatar
    Ron

    Help pls.. I installed the wp blog using the script, runs fine but im having an error in uploading my WP XML file to upload my posts etc. Error says “Zero Sized Reply” in my browser. Is that error related to the bootstrapscript?

    • Ron's avatar
      Ron

      Sorry guys ..i just forgot to set permissions in wp-content/uploads dir.
      chmod 755 uploads/ fix it.
      BTW i think we can still tune PHP to use less memory in /etc/php5/cgi/php.ini memory_limit = 128M
      and set memory limit to 64.

      • LEA's avatar
        LowEndAdmin Author

        That’s the maximum memory that PHP can use, but not necessarily the amount that it would use during an execution of a script.

        • Ron's avatar
          Ron

          ok ..after i rebooted my vps php-fcgi dont auto start. have i missed something in the script?

  15. Jackk's avatar
    Jackk

    Any idea how to restart the PHP processes? I am having to restart the whole system at the moment.

  16. sarim khan's avatar
    sarim khan

    I am now running cherokee in debian. And i am using debian “sid” repo. But cherokee is suffering very much. after few hours every time it shows “504 gateway timeout”. Then i need to do /etc/init.d/cherokee restart to solve this, but after a few hours problem again arises. When i am out of my home, my site remains unavailable for this 504 … error.

    Now i want to switch to nginx using this script. I read the whole script and tried setting up nginx and php5-cgi but failed.

    How can i make use of this script on an running server like me and any help for sid repo ?

  17. Christian's avatar
    Christian

    Great script!
    I’m using 49 MB on Debian with 2 wordpress sites. amazing.

  18. Marikh's avatar
    Marikh

    Where I can edit nginx .c files? I can’t find them.

    • KLIKLI's avatar
      KLIKLI

      Weird comment organization… these comment is placed over the 9/10 ones..

      Anyway, the NGINX seems to be installed via respiratory (apt-get)
      If you wish to edit them you’ll need to compile NGINX manually.

  19. Ronnie's avatar
    Ronnie

    Hi LEA,

    I use Debian 5 x86 VPS and install LowEndBox shell as this blog said. I could run WordPress and display static webpage very well.

    However, if I browse a PHP webpage under /var/www/nginx-default folder by browser, the browser would download the PHP file, not display it.

    Could you please tell me how to fix it?

    Thanks!

  20. Tom's avatar
    Tom

    LEA, maybe you have anything like fail2ban preconfigured for dropbear?

    • LEA's avatar
      LowEndAdmin Author

      Nope, although fail2ban should be quite configurable to parse syslog file to catch the dropbear error message. I just haven’t really had a need to it yet as most my VPS have port 22 firewalled to specific IPs.

      • addictinggames88.com's avatar
        addictinggames88.com

        Here is the fail2ban conf for dropbear

        Edit fail2ban jail conf
        ——————————————————————–
        # vim /etc/fail2ban/jail.conf
        ——————————————————————–
        bantime = 3600
        findtime = 300

        ## Add dropbear jail at end of file
        [dropbear]

        enabled = true
        port = ssh
        filter = dropbear
        logpath = /var/log/messages
        ——————————————————————–

        # cd /etc/fail2ban/filter.d
        # vim dropbear.conf
        ——————————————————————–
        # Fail2Ban configuration file
        #
        # Author: Francis Russell

        [INCLUDES]

        # Read common prefixes. If any customizations available — read them from
        # common.local
        before = common.conf

        [Definition]

        _daemon = dropbear

        # Option: failregex
        # Notes.: regex to match the password failures messages in the logfile. The
        # host must be matched by a group named “host”. The tag “” can
        # be used for standard IP/hostname matching and is only an alias for
        # (?:::f{4,6}:)?(?P\S+)
        # Values: TEXT
        #

        # These match the unmodified dropbear messages. It isn’t possible to match the source of the
        # ‘exit before auth’ messages from an unpatched dropbear.
        #
        failregex = ^%(__prefix_line)slogin attempt for nonexistent user (‘.*’)?from :.*\s*$
        ^%(__prefix_line)sbad password attempt for .+ from :.*\s*$

        # The only line we need to match with the patched dropbear
        # failregex = ^%(__prefix_line)sexit before auth from .*\s*$

        # Option: ignoreregex
        # Notes.: regex to ignore. If this regex matches, the line is ignored.
        # Values: TEXT
        #
        ignoreregex =
        ——————————————————————–

        Test fail2ban for dropbear
        ——————————————————————–
        # fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/dropbear.conf

  21. Anand's avatar
    Anand

    @LEA,
    Sorry again for a noob question. I changed the etc/hosts to point to my domain. How do I create a nameserver for it using the ip given? I just have one ip. For example, If I have to create 5 blogs, do I need 5 ips?

    • tommy's avatar
      tommy

      install bind/nsd3 dns server, you dont need 5 ip address, just use virtualhost.

      • Anand's avatar
        Anand

        Dont know anything about those or how to install them, but will google and try to find out.
        Thanks a lot for the help.

        • tommy's avatar
          tommy

          check howtoforge.com 🙂

      • eLohkCalb's avatar
        eLohkCalb

        To create nameservers, you do need at least 2 IPs (though 1 IP would work by cheating). It’d be good to get a vps from another provider and set that up as secondary, and now you have redundant NS. 🙂

  22. id's avatar
    id

    hey guys, any idea how to set dropbear to allow login using key authentication? i mean no password login, but pair of secret and public key. i did one before but using openssh, not sure how to do with dropbear, especially in this config. thanks. appreciate it 🙂

  23. winloud's avatar
    winloud

    Hi, how can I change the limit of uploading file size,upload speed?

  24. Chris's avatar
    Chris

    This is great! How about adding a change to ownership of the new wordpress directory so that the plugin updates, etc. work properly:

    chown -R www-data: /var/www/wpdirectory.com

    • LEA's avatar
      LowEndAdmin Author

      No. Files shouldn’t be owned by the same owner as the web server. They shouldn’t be owned by root either (my script is a quick hack but you do need proper users). Files owned by web server means they can be overwritten by web server or your PHP process, if there’s a security breach…

      • Jackk's avatar
        Jackk

        Does this mean I should the ownership of the files to www-data on the server and the sites will still work without problems or any further work?

      • Jackk's avatar
        Jackk

        Sorry – I didn’t read that correctly. What should we do to secure our files and server then?

        • LEA's avatar
          LowEndAdmin Author

          My principle is web server + any script environment (PHP for example) should not have write access to anything other than the ones you intend. For example PHP FastCGI processes should not be able to write to any PHP files. It should probably only be able to write to upload directories, which then need to be excluded from PHP execution…

          Way too much to cover in terms of security.

  25. Ruchira Sahan's avatar
    Ruchira Sahan

    I modified a script called lnmp to use new version of nginx it installs
    * Nginx 0.8.53
    * PHP 5.2.14 ( Didn’t updated it to 5.3.x because some web scripts reported to be having problems with 5.3.X branch)
    * Mysql 5.1.48
    * PHPMyAdmin 3.3.7
    * Eaccelerator (optional 1 click install)
    * VsFTPd, PureFTPd (Optional 1 click install)
    * PHP Suhousin Patch

    It uses about 80MB of ram with 4 worker processes on my own site http://www.ruchirablog.com

    Additional details of installation can be found here http://www.ruchirablog.com/nginx-autoinstaller/

  26. Carla Lysak's avatar
    Carla Lysak

    Why is it that the content reminds me of some other identical the one which I just read elsewhere?

  27. earl's avatar
    earl

    anyone know how to enable ipv6 in nginx?

    • KLIKLI's avatar
      KLIKLI

      –with-ipv6 option if you compile NGINX yourself.
      Not sure whether it’s enabled when you get it via apt-get.

      • dannix's avatar
        dannix

        to check this just run

        nginx -V 2>&1 | grep –color=auto with-ipv6

  28. Olaf's avatar
    Olaf

    While testing sime things for a buddy, I had the chance to run the script on a fresh 256MB cloudthing at rackspace cloudserver setup with the debian image they offer.
    Works w/o problems.

    On the debian part I needed to install locales and dpkg-reconfigure them.

  29. openboy's avatar
    openboy

    hello~i used lowendbox nginx php mysql;
    can you help me to set rewrite for wordpress wp super cache?

  30. drmike's avatar
    drmike

    I had to do the wget line as this:

    wget --no-check-certificate http://github.com/lowendbox/lowendscript/raw/master/setup-debian.sh

    Kept complaining about the cert not matching. Didn’t look into fixing the problem. Just wanted to get the file.

    • LEA's avatar
      LowEndAdmin Author

      Yeah. Due to recent Firesheep controversy github has moved everything to HTTPS. Looks like they are using a GoDaddy wildcard SSL to cover *.github.com, which does not actually work in the case of github.com.

  31. Bob's avatar
    Bob

    LowendAdmin, this script is still broken on Ubuntu. PHP will not start up after a reboot. I have tried 10.04, and 10.10. Please fix the script, as it only works properly on Debian (except the WordPress installation, that is broken on Debian, I have to manually create the folders)

  32. Rudolph's avatar
    Rudolph

    Hey, thanks for this script. I’m new to the whole low end box thing and this helped me figure out how to get PHP working with nginx nicely (though I compiled nginx from source for newer features). Debian 5 32-bit with Drupal going is humming along at 42MB. I didn’t know it was possible to install Drupal without a gig of RAM.

Leave a Reply

Before you comment
  • Please use your hosting provider's support system for service issues.
  • Comments may be held temporarily for spam review.
  • Use <pre>...</pre> for terminal output, or link to a paste service.

Your email address will not be published. Required fields are marked *