Running WordPress with Nginx on ArchLinux

I just moved this blog over to Nginx server from Apache httpd server. I’m pretty satisfied with the overall result. I had to take some time to convert my current httpd configuration over to Nginx, since the new server does not support .htaccess or mod_redirects. This is my current requirements for move over:

  • The site is available on both HTTP and HTTPS.
  • “wp-admin” session is forced to use SSL.
  • I have “quicklook” (to check my server status) and “webalizer” directories under the blog, and they are protected by HTTP BasicAuth.
  • HTTP BasicAuth is to be carried out via SSL.
  • To enforce gzip compression on HTTP connection while disabling it on HTTPS.

Basically I followed the ArchLinux wiki for the implementation, and I will briefly describe what I did.

Nginx (pronounced “Engine X”) is a light-weight open-source http server. Its low resource consumption is the primary purpose for the moveover, and it’s suitable for my server on the cloud.

Firstly, I needed to install the package. And installed “php-cgi” package which is used to provide fastcgi interface to PHP.

~$ sudo pacman -S nginx php-cgi

Then, I configured fastcgi daemon, and add it to rc.d. So the following script was needed to be added to /etc/rc.d as “fastcgi”


. /etc/rc.conf
. /etc/rc.d/functions

case "$1" in
	stat_busy 'Starting Fastcgi Server'
	if /usr/bin/php-cgi -b &
		add_daemon fastcgi
		stat_fail	fi
	stat_busy 'Stopping Fastcgi Server'
	[ -e /var/run/daemons/fastcgi ] && kill $(pidof php-cgi) &> /dev/null;
	if [ $? -gt 0 ]; then 
		rm_daemon fastcgi
	$0 stop
	$0 start
	echo "Usage: $0 {start|stop|restart}"

And I gave it an executable permission:

~$ sudo chmod +x /etc/rc.d/fastcgi

What that script does is to have php-cgi process to listen on port 9000. Now, we would be able to start/stop/restart the daemon with “sudo /etc/rc.d/fastcgi start”. But the script will not be automatically started when the unit is rebooted. It needs to be added to /etc/rc.conf. So I added fastcgi to the rc.conf. Here’s the snippet.

DAEMONS=(syslog-ng ... fastcgi nginx ...)

Then I edited the /etc/nginx/conf/nginx.conf file to point to my blog physical directory. We need to add two servers, one for HTTP and one for HTTPS. This is my sample configuration for server myfineblog.local

    server {
        listen       80;
        server_name  myfineblog.local;
        access_log      /var/log/httpd/myfineblog.local-access.log;
        error_log       /var/log/httpd/myfineblog.local-error.log;
        root            /srv/http/myfineblog;
        gzip            on;

        location ~ ^/(wp-admin|quicklook|webalizer)/* {
            rewrite ^/(.*) https://myfineblog.local/$1 permanent;

        location / {
            index  index.html index.htm index.php;
            root                /srv/http/myfineblog;
            if (!-e $request_filename) {
                rewrite ^.+/?(/wp-.*) $1 last;
                rewrite &.+/?(/.*\.php)$ $1 last;
                rewrite ^(.+)$ /index.php?q=$1 last;

        location ~ \.php$ {
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /srv/http/myfineblog/$fastcgi_script_name;
            include        fastcgi_params;

Line 3 defines the server name (so we can configure virtual hosts based on names).
Line 4-5 defines the access logs for this web site.
Line 6 is the physical location of the web site on local system.
Line 7 is used to turn on gzip.
Line 9-11 is redirect to SSL by sending HTTP redirect if the uri contains any of wp-admin or quicklook or webalizer)
Line 13-21 is the definition of website directory and an equivalent scripts for Apache’s mod_rewrite.
Line 23-29 is the connection to the fastcgi daemon we configured above. It is *important* to change the SCRIPT_FILENAME variable to suit the real physical path of the wordpress script.

To enable SSL server, I assume we already have the certificate and key for the website. The configuration looks the same but it will have SSL options enabled and Basic HTTPAuth section for a certain directories.

    server {
        listen          443;
        server_name     myfineblog.local;
        ssl                     on;
        ssl_certificate         /etc/ssl/certs/myfineblog.crt;
        ssl_certificate_key     /etc/ssl/private/myfineblog.key;
        ssl_session_timeout     5m;
        ssl_ciphers             HIGH:MEDIUM;
        ssl_prefer_server_ciphers       on;
        ssl_protocols           SSLv3 TLSv1;

        root                    /srv/http/myfineblog;
        access_log              /var/log/httpd/myfineblog.local-ssl_access.log;
        error_log               /var/log/httpd/myfineblog.local-ssl_error.log debug;
        gzip                    off;

        location ~ ^/(quicklook|webalizer)/* {
                auth_basic      "Private Section";
                auth_basic_user_file    /srv/http/myfineblog/.htpasswd;
        location / {
                index   index.html index.htm index.php;
                root    /srv/http/myfineblog;
        location ~ \.php$ {
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /srv/http/myfineblog/$fastcgi_script_name;
            fastcgi_param  HTTPS on;
            include        fastcgi_params;

This configuration turned on “SSL”, disabling SSLv2 and weak ciphers. It enabled HTTP Basic Authentication for two directories. I disabled gzip on SSL stream. And it tells the fastcgi server to turn HTTPS on.

And started the daemons with “/etc/rc.d/fastcgi start” and “/etc/rc.d/nginx start”.

YQL, Python, and Yahoo Finance

YQL is the way to get information from Web Services using SQL-like queries. It also provides us a console where we can test our queries and generate the REST query. To see how it works, just go to the console page, and enter the following as the YQL statement:

select * from where symbol='FFIV'

And set the output to either “XML” or “JSON”, and click “Test”. I personally prefer JSON and will continue to use JSON throughout the example. I unchecked the “Diagnostics” and emptied the text field next to “JSON”.

The command will fetch the information related to the stock quote FFIV (F5 Networks, NASDAQ) from Yahoo Finance. Inside “Formatted View” window, you will see the result like this:

 'query': {
  'count': '1',
  'created': '2010-07-22T04:59:35Z',
  'lang': 'en-US',
  'results': {
   'quote': {
    'symbol': 'FFIV',
    'Ask': '80.00',
    'AverageDailyVolume': '1699250',
    'Bid': '77.63',
    'AskRealtime': '80.00',
    'BidRealtime': '77.63',
    'BookValue': '11.167',
    'Change_PercentChange': '-3.68 - -4.79%',
    'Change': '-3.68',
    'Commission': null,
    'ChangeRealtime': '-3.68',
    'AfterHoursChangeRealtime': 'N/A - N/A',
    'DividendShare': '0.00',
    'LastTradeDate': '7/21/2010',
    'TradeDate': null,
    'EarningsShare': '1.412',
    'ErrorIndicationreturnedforsymbolchangedinvalid': 'N/A',
    'EPSEstimateCurrentYear': '2.29',
    'EPSEstimateNextYear': '2.71',
    'EPSEstimateNextQuarter': '0.62',
    'DaysLow': '72.48',
    'DaysHigh': '77.74',
    'YearLow': '33.43',
    'YearHigh': '79.21',
    'HoldingsGainPercent': '- - -',
    'AnnualizedGain': '-',
    'HoldingsGain': null,
    'HoldingsGainPercentRealtime': 'N/A - N/A',
    'HoldingsGainRealtime': null,
    'MoreInfo': 'cnsprmiIed',
    'OrderBookRealtime': 'N/A',
    'MarketCapitalization': '5.859B',
    'MarketCapRealtime': null,
    'EBITDA': '188.9M',
    'ChangeFromYearLow': '+39.68',
    'PercentChangeFromYearLow': '+118.70%',
    'LastTradeRealtimeWithTime': 'N/A - 73.11',
    'ChangePercentRealtime': 'N/A - -4.79%',
    'ChangeFromYearHigh': '-6.10',
    'PercebtChangeFromYearHigh': '-7.70%',
    'LastTradeWithTime': 'Jul 21 - 73.11',
    'LastTradePriceOnly': '73.11',
    'HighLimit': null,
    'LowLimit': null,
    'DaysRange': '72.48 - 77.74',
    'DaysRangeRealtime': 'N/A - N/A',
    'FiftydayMovingAverage': '72.3831',
    'TwoHundreddayMovingAverage': '63.8515',
    'ChangeFromTwoHundreddayMovingAverage': '+9.2585',
    'PercentChangeFromTwoHundreddayMovingAverage': '+14.50%',
    'ChangeFromFiftydayMovingAverage': '+0.7269',
    'PercentChangeFromFiftydayMovingAverage': '+1.00%',
    'Name': 'F5 Networks, Inc.',
    'Notes': '-',
    'Open': null,
    'PreviousClose': '76.79',
    'PricePaid': null,
    'ChangeinPercent': '-4.79%',
    'PriceSales': '8.42',
    'PriceBook': '6.88',
    'ExDividendDate': 'N/A',
    'PERatio': '54.38',
    'DividendPayDate': 'N/A',
    'PERatioRealtime': null,
    'PEGRatio': '1.65',
    'PriceEPSEstimateCurrentYear': '33.53',
    'PriceEPSEstimateNextYear': '28.34',
    'Symbol': 'FFIV',
    'SharesOwned': null,
    'ShortRatio': '3.60',
    'LastTradeTime': '4:00pm',
    'TickerTrend': ' -===== ',
    'OneyrTargetPrice': '75.11',
    'Volume': '3213004',
    'HoldingsValue': null,
    'HoldingsValueRealtime': null,
    'YearRange': '33.43 - 79.21',
    'DaysValueChange': '- - -4.79%',
    'DaysValueChangeRealtime': 'N/A - N/A',
    'StockExchange': 'NasdaqNM',
    'DividendYield': null,
    'PercentChange': '-4.79%'

Below that text field, we can find the REST statement which we can use to send query to the server. It looks like this for our query:*'FFIV'%0A%09%09&format=json&

This is how we can fetch stock information using YQL and receive information in JSON. Since this is a public data, we can directly send the REST, otherwise we need the API keys to access the data.

Let’s see how we can fetch the information via Python.

>>> import urllib2
>>> result = urllib2.urlopen('*'FFIV'%0A%09%09&format=json&').read()
>>>  print

That should print the whole JSON response. We can use simplejson module to parse the result. It looks like this:

>>> import simplejson
>>> data = simplejson.loads(
>>> data['query']['results']['quote']['LastTradePriceOnly']

The python statements are pretty much self-explanatory.

Here’s another example from Yahoo, to get stock information from open data tables.