Home > Linux, Testing > WordPress for Raspberry Pi using Nginx and MySQL

WordPress for Raspberry Pi using Nginx and MySQL

I’ve been wondering how the Raspberry Pi would handle WordPress. I’ve found some instructions using Apache 2, but this may not be the best server to use for this type of low-end hardware. nginx server requires less resources, and as it is what I already setup for this blog, I decided to give it a try on the Pi.

I’ll provide all the detailed steps I followed below, but you can also download the compressed SD card image (113 MB), uncompress it and copy it to an SD card the usual way. After the system boots, find your Raspberry Pi’s IP address, type it in your PC’s browser, and you should see the page pictured below. If you want to login to the dashboard, the username is “admin” and the password “raspberry”.

Instructions to Install WordPress on Raspberry Pi

You can use your default Debian Linux distribution (e.g. Raspbian) if space if not an issue, but all what I did below is based on Raspbian minimal image.

Install ngnix, php and mysql in the server:

sudo apt-get update
sudo apt-get install nginx php5-fpm php5-cli php5-curl php5-gd php5-mcrypt php5-mysql php5-cgi mysql-server

You’ll be asked for mysql root password. I used “raspberry” of course!

Create a nginx configuration file for your WordPress blog in /etc/nginx/sites-available/wordpress:

# Upstream to abstract backend connection(s) for php
upstream php {
        server unix:/var/run/php5-fpm.sock;
}

server {

        ## Your only path reference.
        root /srv/www/wordpress/public_html;
        listen          80;
        ## Your website name goes here. Change to domain.ltd in VPS
        server_name     _;

        access_log      /srv/www/wordpress/logs/access.log;
        error_log       /srv/www/wordpress/logs/error.log;

        ## This should be in your http block and if it is, it's not needed here.
        index index.php;

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }

        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        location / {
                # This is cool because no php is touched for static content
                try_files $uri $uri/ /index.php;
        }
        location ~ \.php$ {
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi_params;
                fastcgi_intercept_errors on;
                fastcgi_pass php;
        }

        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
}

Enable your wordpress blog:

sudo ln -s ../sites-available/wordpress ../sites-enabled/wordpress
sudo rm default
sudo rm  ../sites-enabled/default

As mentioned in the note in the config file above, edit /etc/php5/fpm/php.ini to enable the line:

cgi.fix_pathinfo = 0;

You can try if nginx is running properly at this point, first start it:

sudo service nginx start

and try to access it from your PC’s browser using Raspberry Pi IP address (e.g. 192.168.0.106), you should see:

Welcome to nginx!

Now let’s download and extract WordPress into the RPi:

sudo mkdir -p /srv/www/wordpress/logs/
sudo mkdir -p /srv/www/wordpress/public_html
cd /srv/www/wordpress/public_html
sudo wget http://wordpress.org/latest.tar.gz
sudo tar xzvf latest.tar.gz
sudo mv wordpress/* .

Now let’s follow WordPress installation instructions:

$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5340 to server version: 3.23.54

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> CREATE DATABASE wordpress;
Query OK, 1 row affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON wordpress.* TO "wordpress"@"localhost"IDENTIFIED BY "raspi";
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)

mysql> EXIT
Bye
$

In /srv/www/wordpress/public_html directory edit WordPress configuration:

sudo cp wp-config-sample.php wp-config.php
sudo edit wp-config.php

and update the database details as follows:

define('DB_NAME', 'wordpress');
/** MySQL database username */
define('DB_USER', 'wordpress');
/** MySQL database password */
define('DB_PASSWORD', 'raspi');

Finally change the directory permissions and start(or restart) nginx and php5-fpm.

sudo chown www-data.www-data /srv/www/wordpress/public_html/ -R
sudo service nginx restart
sudo service php5-fpm restart

Now access the following IP address in your PC’s web browser

http://192.168.0.106/wp-admin/install.php

Where you need to replace 192.168.0.106 with your Raspberry Pi IP address.

Wordpress Installation Page Rendered on the Raspberry Pi

Fill the details (I used “raspberry” password), click on Install WordPress, and follow the  installation instructions in your browser. You should now be able to login to the Dashboard and create a post. For better performance, I’ve installed W3 Total Cache plugin, and enabled Page, Browser and Object caching. Once caching is enabled, the pages should load immediately (less than a second) for non-logged in users. I did experience one issue with caching enabled but not working. This was solved by clearing my browser cookies. Go figure. Since the dashboard is not cached, editing posts and adding pictures is somewhat slow but still usable.

WordPress Benchmarks on Raspberry Pi

Finally, I’ve done some benchmarks on the main page using ApacheBench from another Linux machine on the LAN with 10 concurrent users making 100 requests:

ab -n 100 -c 10 http://192.168.0.106/
This is ApacheBench, Version 2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.0.106 (be patient).....done

Server Software:        nginx/1.2.1
Server Hostname:        192.168.0.106
Server Port:            80

Document Path:          /
Document Length:        9614 bytes

Concurrency Level:      10
Time taken for tests:   29.091 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      989300 bytes
HTML transferred:       961400 bytes
Requests per second:    3.44 [#/sec] (mean)
Time per request:       2909.116 [ms] (mean)
Time per request:       290.912 [ms] (mean, across all concurrent requests)
Transfer rate:          33.21 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    2   2.0      1      15
Processing:  1003 2820 373.4   2888    3778
Waiting:      959 2763 371.6   2828    3687
Total:       1006 2822 373.2   2889    3792

Percentage of the requests served within a certain time (ms)
  50%   2889
  66%   2907
  75%   2909
  80%   2915
  90%   2928
  95%   2929
  98%   3598
  99%   3792
 100%   3792 (longest request)

With this simple WordPress page, the Raspberry Pi can handle 3.44 Requests per second, which is equivalent to around 12,400 requests per hour or nearly 300,000 requests per day.

You might want to try to further improve performance by using PHP APC and Varnish, or replacing MySQL with SQLite3.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter

  1. myxa78
    August 3rd, 2012 at 16:16 | #1

    i’m running web server on CX-01 via Paw Server + php plugin, it’s working! ;)

  2. August 3rd, 2012 at 17:06 | #2

    If you tried to make this guide as simple as possible, should’ve used wordpress is packaged in debian, http://packages.debian.org/wheezy/wordpress, simply apt-get install wordpress.

  3. August 3rd, 2012 at 18:54 | #3

    @ rm
    Thanks. I did not know WordPress was available as a package.

  4. BarryK
    August 4th, 2012 at 22:17 | #4

    Puppy Linux has PPLOG, which is a single Perl script, that uses it’s own plain-text filing system (no database required).

    This is also in the Puppy port for the Raspberry Pi, but I haven’t actually got around to testing it.

    Here is the official PPLOG website, but note that our script has some enhancements:
    http://code.google.com/p/pplog/

    My own blog is powered by PPLOG:
    http://bkhome.org/blog/

    It is so tiny, most builds of Puppy have it. it is great as a personal blog, even if you don’t want to publish it on the Internet.

    Our package is here:
    http://distro.ibiblio.org/quirky/pet_packages-noarch/pplog-1.1.3.pet

    Regards,
    Barry

  5. max
    August 5th, 2012 at 07:38 | #5

    they have similar thing for android also?

  6. August 5th, 2012 at 09:32 | #6

    @max
    I’m not sure if you meant to reply to myxa78, if not, see the first comment above.

  7. zoobab
    August 16th, 2012 at 21:53 | #7

    wordpress has a static cache plugin if i am not mistaken, that could improve the stats of the apache stress tool.

  8. August 16th, 2012 at 22:11 | #8

    @zoobab
    I used W3 Total Cache, so this benchmark actually shows the performance to serve static pages.

  9. aguedob
    August 24th, 2012 at 01:24 | #9

    I followed you tutorial but it seems that my raspberry is almost ten times slower than yours! Look at my benchmark with only 10 requests. Any clue?

    $ ab -n 10 -c 10 http://192.168.2.251/blog/
    This is ApacheBench, Version 2.3
    Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
    Licensed to The Apache Software Foundation, http://www.apache.org/

    Benchmarking 192.168.2.251 (be patient)…..done

    Server Software: nginx/1.2.1
    Server Hostname: 192.168.2.251
    Server Port: 80

    Document Path: /blog/
    Document Length: 6547 bytes

    Concurrency Level: 10
    Time taken for tests: 35.848 seconds
    Complete requests: 10
    Failed requests: 0
    Write errors: 0
    Total transferred: 67690 bytes
    HTML transferred: 65470 bytes
    Requests per second: 0.28 [#/sec] (mean)
    Time per request: 35847.697 [ms] (mean)
    Time per request: 3584.770 [ms] (mean, across all concurrent requests)
    Transfer rate: 1.84 [Kbytes/sec] received

    Connection Times (ms)
    min mean[+/-sd] median max
    Connect: 6 1715 5398.6 7 17079
    Processing: 0 24990 11966.4 33862 35837
    Waiting: 0 24988 11966.0 33860 35835
    Total: 17079 26705 8806.5 33868 35847

    Percentage of the requests served within a certain time (ms)
    50% 33868
    66% 34585
    75% 34995
    80% 35608
    90% 35847
    95% 35847
    98% 35847
    99% 35847
    100% 35847 (longest request)

  10. August 24th, 2012 at 09:44 | #10

    @aguedob
    Can you check caching is working, by verifying some files are created in wp-content/plugins/w3tc/pgcache or objcache directory? (Not sure exactly of the dir but should be similar).

  11. aguedob
    August 26th, 2012 at 04:25 | #11

    @cnxsoft
    Thanks for the hint. I had a problem with W3TC configuration. Now is really fast ;)

  12. September 9th, 2012 at 03:46 | #12

    raspberrypi (oc 800 Mhz) archlinuxarm + mysql + nginx + php-pfm + apc + w3tc

    local network
    Requests per second: 281.94 [#/sec] (mean)

    internet (ADSL spain)
    Requests per second: 10.85 [#/sec] (mean)

    check here: http://homepi.sytes.net

  13. September 9th, 2012 at 07:34 | #13

    @Raul
    Thanks, I did not know apc could provide such a boost in performance… I should try it on this blog.

  14. Rorto
    September 12th, 2012 at 22:29 | #14

    In the SD image you provide the IP adress for wordpress is 192.168.0.106 and i want to modify it.
    Could you provide ssh access info ?

    Thanks =)

  15. Rorto
    September 13th, 2012 at 05:35 | #15

    @Rorto
    OK it’s pi/raspberry
    Sorry.

  16. October 3rd, 2012 at 07:03 | #16

    Thanks for your installation description for nginx!
    I am installing it to run it on my Rasberry Pi with Joomla :-)

    I had some problems with installing mysql with “sudo apt-get install mysql”

    Only after some searching I found: “sudo apt-get install mysql-server”, and then I noticed that
    you also mentioned “mysql-server” but my browser didn’t display the “-server” part on your site…

  17. Rob
    October 22nd, 2012 at 05:31 | #17

    @aguedob

    Care to share what you did?

  18. tasman
    December 30th, 2012 at 07:04 | #18

    as long as I access the blog within the same network everything is fine (response time ~2-3sec).
    When I try to access it over the internet (I changed WordPress/Settings/General/ home/site URL to my dyndns URL), responses are very slow />30 sec.
    DSL speed shouldn’t be the limiting factor – accessing a static html (that I placed in the public_html folder) over the internet was fast….

    Any ideas?

  19. December 30th, 2012 at 08:43 | #19

    @tasman
    You should try to enable debugging in W3 Total Cache to see if caching really works.
    You could also try some web loading test tools such as http://www.webpagetest.org/, it could help you find out what is wrong.

  20. tasman
    December 30th, 2012 at 19:42 | #20

    @cnxsoft
    Thanks for the link. This helped…in a way:
    I did the test and the strange thing is: after the initial request there are several calls to the local/private IP of my raspberry PI which can’t (and shouldn’t) be resolved.
    But where do these strange URLs come from:
    e.g. http://192.168.2.104/wp-content/themes/twentytwelve/js/html5.js

    I even added my dyndns to WP_HOME and WP_SITEURL in the wp-config.php.

    remark: There seems to be some problem with my router: I can’t connect to my dyndns URL from within the lan. But this shouldn’t be a problem when accessing the wordpress site from the outside, e.g. using the webpagetest.

  21. tasman
    December 30th, 2012 at 21:56 | #21

    @tasman
    after some googling I finally found the solution:

    originally I had the private IP(http://192.168.2.10) configured as site-url and wp-home. Later on I did change them to my dyndns through the admin frontend.
    There seems to be a conflict between entries in the config-file and configuration through the admin frontend:

    When I executed this in mysql (in wordpress db):
    SELECT * FROM `wp_options` WHERE `option_name` IN (‘siteurl’, ‘home’);
    …the result showed that siteurl still contained the private IP. I.e. my config-entries were ignored!

    Finally I updated the db to use my dyndns url.
    update wp_options set option_value = “http://mydomain” where option_name=’siteurl';

    Additionally I updated another table to adjust the previous content-uploads.
    UPDATE wp_posts SET post_content =
    REPLACE(post_content,”http://192.168.2.10″,”http://mydomain”);

    The result: My page loads quite fast and without errors – next step: reactivate the cache!
    Thanks again for your tip regarding webpagetest. This helped a lot.

  22. markmeson
    January 4th, 2013 at 04:57 | #22

    this config file doesn’t work for me. using the one on the nginx site (example for wordpress sites) works fine.

  23. acra
    February 1st, 2013 at 19:19 | #23

    Getting a weird issue – I’m able to navigate to the installer, and go through that successfully. I’m also able to then navigate to the CP and make changes – but as soon as I head to the root site eg subdomain.domain.com my browser simply downloads a file called “download.file” which contains this:

    <?php
    /**
    * Front to the WordPress application. This file doesn't do anything, but loads
    * wp-blog-header.php which does and tells WordPress to load the theme.
    *
    * @package WordPress
    */

    /**
    * Tells WordPress to load the WordPress theme and output it.
    *
    * @var bool
    */
    define('WP_USE_THEMES', true);

    /** Loads the WordPress Environment and Template */
    require('./wp-blog-header.php');

    What am I doing wrong?

  24. acra
    February 1st, 2013 at 20:35 | #24

    @acra
    Found it, I’d made a change in the config but hadn’t cleared my browser cache!

  25. otter9099
    March 19th, 2013 at 05:47 | #25

    Hi,

    I tried your image and I am very impressed with it. Makes the RP very useable as a WordPress Server. However I had to use the same network configuration as you in order to access WordPress (ie 192.168.0.106). Which configuration file holds this setting? My educated guess is it is something in WordPress because the page starts to load using my network settings of 10.0.0.x but the address for WordPress auto changes to 192.168.0.106 and only loads a few text based items. Any help would be much appreciated.

  26. March 19th, 2013 at 09:55 | #26

    @otter9099
    I guess WordPress uses the IP address during installation. I’m not exactly sure where it’s stored, or if it can be changed in the dashboard.
    The fast way could be to install it yourself.

  27. otter9099
    March 21st, 2013 at 10:55 | #27

    @cnxsoft
    Thank you, I will give it a try.

  28. March 26th, 2013 at 04:42 | #28

    Thanks a lot for this guide! I now have my own website running on my Raspberry Pi (I just created the domain some hours ago so it’s not working yet, still waiting :)).

  29. October 7th, 2013 at 21:47 | #29

    @Rorto

    @otter9099

    Gents, you can manually define the site’s URL using the wp-config.php file in the root of the wordpress install.

    sudo nano /srv/www/wordpress/public_html/wp-config.php

    Then, add the following lines to your file, replacing the x’s with your pi’s URL.

    define(‘WP_HOME’,’http://192.168.x.xxx/’);
    define(‘WP_SITEURL’,’http://192.168.x.xxx/’);

  30. February 13th, 2014 at 19:22 | #30

    @Geoff
    Lordy thanks Geoff! Where has this post been for the past year! WP has given me such headaches over IP changes!

  31. Lison
    February 28th, 2014 at 19:53 | #31

    hello,
    i followed this post to build my php environment, and it works with port 80. but now i want change the port to 8000.
    i am fresh with pi and linux, even nginx.

    what i have done is change the settings “listen” in
    “/etc/nginx/sites-enabled”
    and
    “/etc/nginx/sites-available”
    to 8000.

    then i restart nginx and php5-fpm, and i got no iptables. but it not work,i cannot access my site with the http address.

    when i use command: telnet myip 8000, and type Ctrl+C, it shows me 400 bad request.

    can you tell me what should i do? Thank you

  1. August 9th, 2012 at 16:28 | #1
  2. September 24th, 2012 at 19:51 | #2
  3. October 1st, 2012 at 22:26 | #3
  4. December 1st, 2012 at 23:37 | #4
  5. December 9th, 2012 at 06:17 | #5
  6. February 22nd, 2013 at 23:30 | #6
  7. February 28th, 2013 at 15:26 | #7
  8. May 20th, 2013 at 17:12 | #8