Setting Up WordPress Like a Pro

Setting up WordPress is something you learn early on and don’t really think about – it becomes second nature.

A complete professional installation and configuration can contain a lot longer than the famous 5-minute install!

From .htaccess security to automated deployment, I’ll take you through some amazing methods you can use to create a WordPress environment fit for pros.

Installing WordPress

Let’s get this one out of the way by looking at all the different ways you can create a WordPress installation.

The 5 Minute Install

The “Famous 5 Minute Installation” has been around forever. It involves the following:

  • Uploading WordPress zip file
  • Extracting the zip
  • Creating the database tables
  • Creating the configuration file
  • Running the install

More details about this can be found on the Installing WordPress Codex page. There’s nothing wrong with this method, but it can get a bit clunky and isn’t convenient for some people.

For example: not all hosts have GUI tools that allow you to unzip files on the server. If this is the case you’ll need to use SSH access since unzipping cannot be done from your FTP client. Your other option is to upload the unzipped files, which takes a bit longer than forever. I think we can do better.

Terminal Installation

You knew it was coming, the dreaded terminal! If you’re on Linux or Mac you’ll be able to do the above from the terminal, for Windows you’ll need to use PuTTY.

The first step is to grab all WordPress files. The code below seems lengthy but apart from the first two lines it is copy-pastable so you can get all the files you need in a few seconds.

1
2
3
4
5
6
7
ssh [email protected]
cd /path/to/installation/directory
wget http://wordpress.org/latest.zip
unzip latest.zip
mv wordpress/* ./
rmdir wordpress
rm latest.zip

Once we SSH into our server and change directories we use the wget command to download the latest version of WordPress; then we unzip it. Since this puts all the files in a wordpress subdirectory we need to move all files into the parent directory. We then finish up by deleting the unwanted subdirectory and the original zip file.

At this point you can set up the database in your cPanel and edit the config file using an FTP editor but let’s take a look at how we can get all that done in the terminal as well. Let’s turn our attention to the database:

1
mysql -u username -p

If you enter this line (replacing “username” with your actual username) you should be prompted for your password, after which you will arrive in the MySQL console. From here you can create the database by issuing the following SQL command.

1
create database mywordpressdb;

The final step is creating the config file. You can get this done by copying or moving the sample file and editing it using vim. I like to move the file because this gets rid of the sample file, there’s no need to keep it.

1
2
mv wp-config-sample.php wp-config.php
vi wp-config.php

If you’re not familiar with VIM I suggest taking a look at the basics. I don’t use it a lot myself, but knowing the minimum to navigate and edit a file is a great time saver when working on a remote server. Put very simply: press i to go into insert mode. Navigation around using the arrows, edit as needed. When done, press escape then type :wq and press enter; this will save and quit.

There we have it, all done. While this took a while to describe, it is actually much faster than the 5 minute install once you’ve done it at least once. It saves you the time of switching to multiple tools at the very least.

WP-CLI

WP-CLI pops up in many of my tutorials because it can be used for so many things! WP-CLI is a command line tool which allows you to interact with your WordPress environment. This includes everything from creating 100 test users with a line of code to installing and updating WordPress.

The instructions for installing WP-CLI are not difficult at all, a few terminal commands will get it done. Once installed you can start running commands. SSH into your server and go to the installation directory.

1
2
3
4
wp core download
wp core config --dbname=yourdb --dbuser=yourdbuser --dbpass=yourdbpass --dbhost=youdbhost --dbprefix=yourdbprefix
wp db create
wp core install --url=yoursiteurl --title=sitetitle --admin_user=username --admin_password=password --admin_email=youremail

That’s all there is to it, you now have a fully installed and configured WordPress website. WP-CLI is my method of choice, I will be using it to install plugins and make some other modifications further in the post.

Configuration

There are a number of things you can do pre-installation and during the installation process to make your site more secure and perform better. Here’s a list of what I tend to use – the options here are endless.

Be Unpredictable

Unpredictability is a great way to sidestep a whole lot of security issues. Don’t leave that database prefix as “wp_”, don’t use the “admin” username, and so on. Here’s why: since a lot of sites have a username of “admin”, hackers have a piece of the puzzle when it comes to getting into your site. Even worse, they have the username of an admin user!

Since hackers don’t have direct access to your site they don’t know what usernames you have, they don’t know your database prefix and so on. All they can do is hope that you’re using the defaults. Here’s a list of things I modify to make my sites a bit safer.

  • My database prefix is usually like a mini password. Instead of “wp_” I use something like “Hjd9_3jdpq3GQ4_”
  • I use a separate admin use which I only use when I need to perform admin tasks, otherwise I use an editor or author.
  • My admin user also has a non-standard name. This doesn’t have to be as complex, even something like “danieladmin” would do.
  • Needless to say that none of the passwords to my sites are “1234”. Strong passwords are your best defence, use at least 8 characters with an uppercase letter, lowercase letter, number and a symbol.

.htaccess Firewall

This is the first line of defence I add to all my sites. The code I use was/is developed by Jeff Star, it is called the G6 Firewall. This version is currently in beta and is the successor to the 5G Firewall.

All you need to do is paste the contents of the firewall into the .htaccess file in the root directory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 6G BLACKLIST/FIREWALL (beta)
# @ http://perishablepress.com/6g-beta/

# 6G:[REQUEST STRINGS]
<ifModule mod_alias.c>
 RedirectMatch 403 /(\$|\*)/?$
 RedirectMatch 403 (?i)(<|>|:|;|\'|\s)
 RedirectMatch 403 (?i)([a-zA-Z0-9]{18})
 RedirectMatch 403 (?i)(https?|ftp|php)\:/
 RedirectMatch 403 (?i)(\"|\.|\_|\&|\&amp)$
 RedirectMatch 403 (?i)(\=\\\'|\=\\%27|/\\\'/?)\.
 RedirectMatch 403 (?i)/(author\-panel|submit\-articles)/?$
 RedirectMatch 403 (?i)/(([0-9]{5})|([0-9]{6}))\-([0-9]{10})\.(gif|jpg|png)
 RedirectMatch 403 (?i)(\,|//|\)\+|/\,/|\{0\}|\(/\(|\.\.|\+\+\+|\||\\\"\\\")
 RedirectMatch 403 (?i)/uploads/([0-9]+)/([0-9]+)/(cache|cached|wp-opt|wp-supercache)\.php
 RedirectMatch 403 (?i)\.(asp|bash|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf|well)
 RedirectMatch 403 (?i)/(^$|1|addlink|btn_hover|contact?|dkscsearch|dompdf|easyboard|ezooms|formvars|fotter|fpw|i|imagemanager|index1|install|iprober|legacy\-comments|join|js\-scraper|mapcms|mobiquo|phpinfo|phpspy|pingserver|playing|postgres|product|register|scraper|shell|signup|single\-default|t|sqlpatch|test|textboxes.css|thumb|timthumb|topper|tz|ucp_profile|visit|webring.docs|webshell|wp\-lenks|wp\-links|wp\-plugin|wp\-signup|wpcima|zboard|zzr)\.php
 RedirectMatch 403 (?i)/(\=|\$\&|\_mm|administrator|auth|bytest|cachedyou|cgi\-|cvs|config\.|crossdomain\.xml|dbscripts|e107|etc/passwd|function\.array\-rand|function\.parse\-url|livecalendar|localhost|makefile|muieblackcat|release\-notes|rnd|sitecore|tapatalk|wwwroot)
 RedirectMatch 403 (?i)(\$\(this\)\.attr|\&pws\=0|\&t\=|\&title\=|\%7BshopURL\%7Dimages|\_vti\_|\(null\)|$itemURL|ask/data/ask|com\_crop|document\)\.ready\(fu|echo.*kae|eval\(|fckeditor\.htm|function.parse|function\(\)|gifamp|hilton.ch|index.php\&amp\;quot|jfbswww|monstermmorpg|msnbot\.htm|netdefender/hui|phpMyAdmin/config|proc/self|skin/zero_vote|/spaw2?|text/javascript|this.options)
</ifModule>

# 6G:[QUERY STRINGS]
<IfModule mod_rewrite.c>
 RewriteCond %{REQUEST_URI} !^/$ [NC]
 RewriteCond %{QUERY_STRING} (mod|path|tag)= [NC,OR]
 RewriteCond %{QUERY_STRING} ([a-zA-Z0-9]{32}) [NC,OR]
 RewriteCond %{QUERY_STRING} (localhost|loopback|127\.0\.0\.1) [NC,OR]
 RewriteCond %{QUERY_STRING} (\?|\.\./|\*|:|;|<|>|'|"|\)|\[|\]|=\\\'$|%0A|%0D|%22|%27|%3C|%3E|%00|%2e%2e) [NC,OR]
 RewriteCond %{QUERY_STRING} (benchmark|boot.ini|cast|declare|drop|echo.*kae|environ|etc/passwd|execute|input_file|insert|md5|mosconfig|scanner|select|set|union|update) [NC]
 RewriteRule .* - [F,L]
</IfModule>

# 6G:[USER AGENTS]
<ifModule mod_setenvif.c>
 #SetEnvIfNoCase User-Agent ^$ keep_out
 SetEnvIfNoCase User-Agent (<|>|'|<|%0A|%0D|%27|%3C|%3E|%00|href\s) keep_out
 SetEnvIfNoCase User-Agent (archiver|binlar|casper|checkprivacy|clshttp|cmsworldmap|comodo|curl|diavol|dotbot|email|extract|feedfinder|flicky|grab|harvest|httrack|ia_archiver|jakarta|kmccrew|libwww|loader|miner|nikto|nutch|planetwork|purebot|pycurl|python|scan|skygrid|sucker|turnit|vikspider|wget|winhttp|youda|zmeu|zune) keep_out
 <limit GET POST PUT>
  Order Allow,Deny
  Allow from all
  Deny from env=keep_out
 </limit>
</ifModule>

# 6G:[REFERRERS]
<IfModule mod_rewrite.c>
 RewriteCond %{HTTP_REFERER} (<|>|'|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
 RewriteCond %{HTTP_REFERER} ([a-zA-Z0-9]{32}) [NC]
 RewriteRule .* - [F,L]
</IfModule>

# 6G:[BAD IPS]
<Limit GET POST PUT>
 Order Allow,Deny
 Allow from all
 # uncomment/edit/repeat next line to block IPs
 # Deny from 123.456.789
</Limit>

There is one tiny modification I have made – I removed a rewrite condition since it prevented scripts and styles from loading. Be aware that you may need to tweak this a tiny bit to make it work in all situations.

If you visit a page in the admin or update a plugin and you get a 403 or similar error where you shouldn’t, your firewall is blocking something it isn’t supposed to. Troubleshooting this is not difficult though.

Keep deleting lines from your .htaccess firewall rules until it works again: you have found the troublesome line. You can delete the line altogether or modify it to make sure it doesn’t catch the legitimate action you are taking.

This has only happened to me only a couple of times and in my experience the benefits of this firewall far outweigh the tweaking you need to do.

Additional WordPress Configuration Options

The wp-config.php can contain a lot more than meets the eye. Take a look at the Codex for the whole picture, I’ll highlight some of the additions I make to my config file.

1
2
3
4
5
define( 'AUTOSAVE_INTERVAL', 300 );
define( 'WP_POST_REVISIONS', false );
define( 'EMPTY_TRASH_DAYS', 7 );
define( 'DISALLOW_FILE_EDIT', true );
define( 'FORCE_SSL_ADMIN', true );

As you can see I’ve increased the autosave interval to 160 seconds instead of 60. I really don’t have the need to save every minute. I’ve also disabled post revisions since I never use them. I made sure the trash is emptied every seven days instead of 30. By defining the DISALLOW_FILE_EDIT the theme/plugin editing features are completely disabled in the admin. I usually force SSL admins which can be a bit slower, but the added protection is worth it.

At the end of the article I’ll show you how you can add these definitions to your configuration file automatically using WP-CLI.

  • Amazon S3 And Cloudfront

    amazonwithcludfront

    I use this plugin in almost all my projects because it mirrors all media items to Amazon S3 and server them from there. This offers two huge benefits.

    • Load times will be lower, especially if you use the Cloudfront CDN as well.
    • Since media is served from an external source moving a site becomes a lot easier and I can use the same media on a local test without needing to download a single file

    Setup is extremely easy as well. Create a bucket and point the plugin to that bucket, that’s it! The plugin contains instructions for integrating with Cloudfront which is also easy to do.

    Interested in Amazon S3 And Cloudfront?

  • Akismet

    akismet

    Akismet is great at reducing the spam you get in your comments. Processing is all done off your server – you just get the goodness of Akismet’s experience with millions of websites.

    Setup requires an Akismet API key but you can grab this for free. If you use Akismet for business purposes please do consider supporting them with whatever you can, they do a great job over there!

    Interested in Akismet?

  • W3 Total Cache

    w3totalcache

    W3 Total Cache is an all-in-one caching solution, which allows you to increase your sites speed easily. It is filled with tons of options so you can customize caching to your needs exactly.

    Many people use a popular alternative plugin named WP Super Cache. In my opinion W3 Total Cache is a bit more modern, but both are great plugins.

    Interested in W3 Total Cache?

  • Jetpack

    jetpack

    Jetpack is a huge plugin which provides a lot of features that you can selectively enable/disable. From contact forms to sharing, infinite scroll to related posts you’re bound to find something you need.

    In all honesty Jetpack is not something I always install. The codebase is considerably larger than that of WordPress itself and it does have a lot of unnecessary bloat.

    That being said, Jetpack was made by WordPress so you can be sure it won’t bog your site down unnecessarily, especially since what you don’t need can be deactivated.

    Interested in Jetpack?

  • VaultPress

    vaultpress

    VaultPress is truly a must-have plugin for me. While this is a paid service it is a no-brainer due to the usefulness of it. I pay $5 a month for complete daily backups with a 30 day archive.

    What makes VaultPress so invaluable is the set-and-forget nature of it, coupled with a painless installation process. Since I always use Amazon S3 to store media, backing up the remaining parts of my website would not be that difficult.

    VaultPress just makes things so easy it’s better to leave everything up to it. If something does go wrong, rolling back is just a click away.

    Interested in VaultPress?

  • Google XML Sitemaps

    google-xml-sitemaps

    Sitemaps are for search engines’ eyes, they contain the structure of website. Google XML sitemaps was built to create a fully Google-compliant sitemap which will make it easier for search engines to map and index your site.

    Interested in Google XML Sitemaps?

  • Limit Login Attempts

    limit-login-attempts

    This great plugin gives you an additional layer of security by limiting the number of times users can try to log in. Not a huge feature list, but it does its task very well.

    Interested in Limit Login Attempts?

  • All In One SEO Pacl

    allinoneseo

    SEO is a huge part of building a presence on the web. Plugins like All In One SEO Pack help you control the optimization of your website by showing you keyword analysis, allowing you to set meta attributes and a whole lot more.

    WordPress SEO by Yoast is also a hugely popular alternative, both great choices.

    Interested in All In One SEO Pacl?

  • iThemes Security

    ithemessecurity

    iThemes security (formerly known as Better WP Security) is great as an additional layer of security for your WordPress installation. It can do things like change the URL of your admin area, monitor files for changes, scan for vulnerabilities and more.

    Interested in iThemes Security?

Plugin Installation

You could install these plugins via the WordPress admin but this is very wasteful. Not only do you have to wait for each install to finish, you need to search for each plugin and navigate through multiple pages for each installation process. WP-CLI makes this a lot easer, here’s one command which will install al of the plugins above:

1
wp plugin install amazon-s3-and-cloudfront akismet w3-total-cache jetpack vaultpress google-sitemap-generator limit-login-attempts

Putting it All Together

Coming full circle, let’s take a look at how you can automate all of this using a bash script. The bash script will use WP-CLI to take care of our WordPress installation (plugins and all), it will even create our .htaccess file for us. Let’s jump right in by creating an “install.sh” file in the intended installation directory and adding the following contents.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/bin/bash
# Setup Variables

DBNAME=mydatabase
DBUSER=databaseuser
DBPASS=dnpass
DBHOST=localhost
DBPREFIX=C8v8D2_eomGf_

URL=http://urlofsite.com
TITLE=SiteTitle
ADMINUSER=danielpataki
ADMINPASS=mypassword
[email protected]

REPOPLUGINS=&amp;amp;quot;amazon-s3-and-cloudfront w3-total-cache jetpack vaultpress google-sitemap-generator limit-login-attempts&amp;amp;quot;

# Create Htaccess File With Firewall

cat > .htaccess << "EOF"
<ifModule mod_alias.c>
 RedirectMatch 403 /(\$|\*)/?$
 RedirectMatch 403 (?i)(<|>|:|;|\'|\s)
 RedirectMatch 403 (?i)([a-zA-Z0-9]{18})
 RedirectMatch 403 (?i)(https?|ftp|php)\:/
 RedirectMatch 403 (?i)(\"|\.|\_|\&|\&amp)$
 RedirectMatch 403 (?i)(\=\\\'|\=\\%27|/\\\'/?)\.
 RedirectMatch 403 (?i)/(author\-panel|submit\-articles)/?$
 RedirectMatch 403 (?i)/(([0-9]{5})|([0-9]{6}))\-([0-9]{10})\.(gif|jpg|png)
 RedirectMatch 403 (?i)(\,|//|\)\+|/\,/|\{0\}|\(/\(|\.\.|\+\+\+|\||\\\"\\\")
 RedirectMatch 403 (?i)/uploads/([0-9]+)/([0-9]+)/(cache|cached|wp-opt|wp-supercache)\.php
 RedirectMatch 403 (?i)\.(asp|bash|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rar|rdf|well)
 RedirectMatch 403 (?i)/(^$|1|addlink|btn_hover|contact?|dkscsearch|dompdf|easyboard|ezooms|formvars|fotter|fpw|i|imagemanager|index1|install|iprober|legacy\-comments|join|js\-scraper|mapcms|mobiquo|phpinfo|phpspy|pingserver|playing|postgres|product|register|scraper|shell|signup|single\-default|t|sqlpatch|test|textboxes.css|thumb|timthumb|topper|tz|ucp_profile|visit|webring.docs|webshell|wp\-lenks|wp\-links|wp\-plugin|wp\-signup|wpcima|zboard|zzr)\.php
 RedirectMatch 403 (?i)/(\=|\$\&|\_mm|administrator|auth|bytest|cachedyou|cgi\-|cvs|config\.|crossdomain\.xml|dbscripts|e107|etc/passwd|function\.array\-rand|function\.parse\-url|livecalendar|localhost|makefile|muieblackcat|release\-notes|rnd|sitecore|tapatalk|wwwroot)
 RedirectMatch 403 (?i)(\$\(this\)\.attr|\&pws\=0|\&t\=|\&title\=|\%7BshopURL\%7Dimages|\_vti\_|\(null\)|$itemURL|ask/data/ask|com\_crop|document\)\.ready\(fu|echo.*kae|eval\(|fckeditor\.htm|function.parse|function\(\)|gifamp|hilton.ch|index.php\&amp\;quot|jfbswww|monstermmorpg|msnbot\.htm|netdefender/hui|phpMyAdmin/config|proc/self|skin/zero_vote|/spaw2?|text/javascript|this.options)
</ifModule>

# 6G:[QUERY STRINGS]
<IfModule mod_rewrite.c>
 RewriteCond %{REQUEST_URI} !^/$ [NC]
 RewriteCond %{QUERY_STRING} (mod|path|tag)= [NC,OR]
 RewriteCond %{QUERY_STRING} ([a-zA-Z0-9]{32}) [NC,OR]
 RewriteCond %{QUERY_STRING} (localhost|loopback|127\.0\.0\.1) [NC,OR]
 RewriteCond %{QUERY_STRING} (\?|\.\./|\*|:|;|<|>|'|"|\)|\[|\]|=\\\'$|%0A|%0D|%22|%27|%3C|%3E|%00|%2e%2e) [NC,OR]
 RewriteCond %{QUERY_STRING} (benchmark|boot.ini|cast|declare|drop|echo.*kae|environ|etc/passwd|execute|input_file|insert|md5|mosconfig|scanner|select|set|union|update) [NC]
 RewriteRule .* - [F,L]
</IfModule>

# 6G:[USER AGENTS]
<ifModule mod_setenvif.c>
 #SetEnvIfNoCase User-Agent ^$ keep_out
 SetEnvIfNoCase User-Agent (<|>|'|<|%0A|%0D|%27|%3C|%3E|%00|href\s) keep_out
 SetEnvIfNoCase User-Agent (archiver|binlar|casper|checkprivacy|clshttp|cmsworldmap|comodo|curl|diavol|dotbot|email|extract|feedfinder|flicky|grab|harvest|httrack|ia_archiver|jakarta|kmccrew|libwww|loader|miner|nikto|nutch|planetwork|purebot|pycurl|python|scan|skygrid|sucker|turnit|vikspider|wget|winhttp|youda|zmeu|zune) keep_out
 <limit GET POST PUT>
  Order Allow,Deny
  Allow from all
  Deny from env=keep_out
 </limit>
</ifModule>

# 6G:[REFERRERS]
<IfModule mod_rewrite.c>
 RewriteCond %{HTTP_REFERER} (<|>|'|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
 RewriteCond %{HTTP_REFERER} ([a-zA-Z0-9]{32}) [NC]
 RewriteRule .* - [F,L]
</IfModule>

# 6G:[BAD IPS]
<Limit GET POST PUT>
 Order Allow,Deny
 Allow from all
 # uncomment/edit/repeat next line to block IPs
 # Deny from 123.456.789
</Limit>

# Install WordPress
wp core download;
wp core config --dbname=${DBNAME} --dbuser=${DBUSER} --dbpass=${DBPASS} --dbhost=${DBHOST} --dbprefix=${DBPREFIX} --extra-php &amp;amp;lt;&amp;amp;lt;PHP
define( 'AUTOSAVE_INTERVAL', 300 );
define( 'WP_POST_REVISIONS', false );
define( 'EMPTY_TRASH_DAYS', 7 );
define( 'DISALLOW_FILE_EDIT', true );
define( 'FORCE_SSL_ADMIN', true );
define( 'AWS_ACCESS_KEY_ID', 'MYAWSKEY' );
define( 'AWS_SECRET_ACCESS_KEY', 'MYAWSSECRET' );
PHP
wp db create
wp core install --url=${URL} --title=${TITLE} --admin_user=${ADMINUSER} --admin_password=${ADMINPASS} --admin_email=${ADMINEMAIL}

# Install Repo Plugins
wp plugin install ${REPOPLUGINS} --activate

# Misc Cleanup
wp post delete 1
wp plugin delete hello-dolly
wp rewrite structure "/%year%/%monthnum%/%day%/%postname%/"
wp rewrite flush

That’s a bit of a mouthful, but you can get by without modifying the code, just the variables on top for each installation. Let’s break it down!

First, we define variables we’ll use throughout the script. The purpose of this is to make it as reusable as possible. Then, we create the .htaccess file and add the firewall code to it.

The next step is to install WordPress itself. We download the files and create the config file, based on our defined variables. Note that I’ve added additional code to the config file. I defined the constants we talked about and I added my Amazon key and secret, which is used by the Amazon S3 plugin. The database is created and the install procedure is run.

The next step installs all the plugins I mentioned. I keep a list of these in a variable as sometimes I will want to add or remove some of them. Note that Akismet is not in this list because it comes bundled with WordPress.

Finally we delete the Hello World post, the Hello Dolly plugin, change the rewrite structure to the year/month/day format and flush the rewrite rules.

Once our script is ready it can be run by entering the following command:

1
bash install.sh

Conclusion

As you’ve seen here it is possible to download, configure, install, secure and optimize WordPress with just one simple command from the terminal.

You may need to tweak some of your sites, but compared to the 30 minutes or so this would take otherwise, this 30 second method ain’t that bad!

As always, remember to make this example your own! Do you have any other plugins you recommend? Do you do things differently or do you have an even better or faster way to install WordPress? Let us know in the comments.

Image Credit: Keoni Cabrai