Blog Migration / Setting Up WordPress on nginx

Recently, I have begun hosting several web services on my home network, and have a few projects I’d like to be able to host. I have been hosting my sites on Amazon for a few years, but now that I have a reliable setup, I figured it was time to migrate everything internally. Unfortunately, my current services each have their own servers, and are distinct enough in purpose that pooling them (or new ones) would not make much sense. Most of my upcoming projects will be websites (and it opens up the potential for additional income).

On to my nginx configuration and WordPress install.

I started with a bare CentOS server, added the nginx repo, and installed all the necessary software for this project.

#add nginx repo
cat > /etc/yum.repos.d/nginx.repo << \EOF
name=nginx repo

#install nginx
yum -y install nginx

#install necessary software
yum -y install wget mysql-server php-fpm php-xml php-mysql

Now that we have all the required software, we can start to configure it. I'm going to start with the database, but WordPress won't work until all of these steps are completed, no matter what order.

chkconfig mysqld on
service mysqld start

mysql -u root -p
> CREATE DATABASE wordpress;
> GRANT ALL PRIVILEGES ON wordpress.* TO "wordpress"@"localhost" IDENTIFIED BY "password";

And now, configure PHP to provide a pool and work within the permissions of nginx, by editing /etc/php-fpm.d/www.conf

listen = /var/run/php5-fpm.sock
user = nginx
group = nginx

chkconfig php-fpm on
service php-fpm start

Ok, time to install WordPress:

mkdir -p /var/www/blog/{htdocs,logs}

#download wordpress
cd /var/www/blog/htdocs/
tar --strip-components=1 -xvf latest.tar.gz

#update permissions
cd /var/www/blog/htdocs/
chown -R root:root .
chown -R nginx:nginx wp-content wp-admin/update* wp-admin/network/update*

And, finally, configure nginx:

cat > /etc/nginx/php.conf << \EOF
location ~ \.php {
        # for security reasons the next line is highly encouraged
        try_files $uri =404;

        fastcgi_param  QUERY_STRING       $query_string;
        fastcgi_param  REQUEST_METHOD     $request_method;
        fastcgi_param  CONTENT_TYPE       $content_type;
        fastcgi_param  CONTENT_LENGTH     $content_length;

        fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;

        # if the next line in yours still contains $document_root
        # consider switching to $request_filename provides
        # better support for directives such as alias
        fastcgi_param  SCRIPT_FILENAME    $request_filename;

        fastcgi_param  REQUEST_URI        $request_uri;
        fastcgi_param  DOCUMENT_URI       $document_uri;
        fastcgi_param  DOCUMENT_ROOT      $document_root;
        fastcgi_param  SERVER_PROTOCOL    $server_protocol;

        fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
        fastcgi_param  SERVER_SOFTWARE    nginx;

        fastcgi_param  REMOTE_ADDR        $remote_addr;
        fastcgi_param  REMOTE_PORT        $remote_port;
        fastcgi_param  SERVER_ADDR        $server_addr;
        fastcgi_param  SERVER_PORT        $server_port;
        fastcgi_param  SERVER_NAME        $server_name;

        # If using a unix socket...
        fastcgi_pass unix:/var/run/php5-fpm.sock;

        # If using a TCP connection...

cat > /etc/nginx/drop.conf << \EOF
location = /robots.txt  { access_log off; log_not_found off; }
location = /favicon.ico { access_log off; log_not_found off; }
location ~ /\.          { access_log off; log_not_found off; deny all; }
location ~ ~$           { access_log off; log_not_found off; deny all; }

cat > /etc/nginx/conf.d/blog.conf << \EOF
server {

        root            /var/www/blog/htdocs;
        index           index.php;

        access_log      /var/log/nginx/blog.access.log;
        error_log       /var/log/nginx/blog.error.log;

        location / {
                try_files $uri $uri/ /index.php;

        location @rewrites {
                rewrite ^ /index.php last;

        # This block will catch static file requests, such as images, css, js
        # The ?: prefix is a 'non-capturing' mark, meaning we do not require
        # the pattern to be captured into $1 which should help improve performance
        location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
                expires max;
                add_header Pragma public;
                add_header Cache-Control "public, must-revalidate, proxy-revalidate";

        # remove the robots line if you want to use wordpress' virtual robots.txt
        location = /robots.txt  { access_log off; log_not_found off; }
        location = /favicon.ico { access_log off; log_not_found off; }

        # this prevents hidden files (beginning with a period) from being served
        location ~ /\.          { access_log off; log_not_found off; deny all; }

        include php.conf;

#Ready to configure WordPress
cp /var/www/blog/htdocs/wp-config{-sample,}.php
chown -R nginx:nginx /var/www/blog/htdocs/wp-config.php
sed -i -e 's/database_name_here/wordpress/' wp-config.php
sed -i -e 's/username_here/wordpress/' wp-config.php
sed -i -e 's/password_here/wordpresspassword/' wp-config.php
SALT=$(curl -L
STRING='put your unique phrase here'
printf '%s\n' "g/$STRING/d" a "$SALT" . w | ed -s wp-config.php
sed -i -e 's/\r$//' wp-config.php

To make sure we can get to the server:

COUNT=`expr $(iptables -L INPUT | wc -l) - 2`; iptables -I INPUT $COUNT -m state --state NEW -p tcp --dport 80 -j ACCEPT

At this point, just navigate to the WordPress site,, and follow the prompts. Permissions should all be set appropriately so that everything should be possible from the site itself.


Leave a Comment

Your email address will not be published.