Walkthrough: Setting up a Secure WordPress Site with Git – Part 1

This article is a walkthrough on the steps to setup a fairly secure* WordPress site leveraging git to make updates easier. It is the result of a set of best practices that I follow when setting up a new WordPress site.

This is not a guarantee of a “hackproof” WordPress site. It is merely a tutorial based on best practices that I have evolved over time. Following these instructions will provide a more secure, better protected WordPress site but it does not confer any kind of magical or technical immunity.

Experience Prerequisites

This is a medium-level tutorial and assumes some basic knowledge about using git and working with both the command line and SQL directly. I will provide links to resources where I can and am happy to answer questions in the comments if you have them. If you have previous experience installing WordPress it will be easier to use but it should be accessible to new users who already have some technical expertise.


We will be covering the following topics in detail as we walk through this series. In addition, I have committed everything to GitHub at https://github.com/bookwyrm/secure-wordpress-setup so you can review the history or see setup details there if you want.

Part 1

  • WordPress Setup with Git
  • Cleaning up Themes and Plugins
  • Pre-Install Security and Config

Part 2

  • WordPress Installation
  • Post-Install Plugins and Configuration
  • Keeping on Top of Updates

WordPress Setup with Git

I like using Git to manage WordPress because it is much easier to manage updates to WordPress.

Setup Git Repository

First we need a local git repo to work with. This will essentially be the document root of a website assuming that you aren’t running your WordPress site in a subdirectory.

[gist id=”2b8b123f1a7079c250cc” file=”setup-git-repo.sh”]

Add WordPress as Submodule

This is where the major benefit of using git comes in. WordPress is added as a git submodule so that it is much easier to upgrade when newer versions are released.

[gist id=”2b8b123f1a7079c250cc” file=”setup-wordpress-submodule.sh”]

Initial WordPress Config

Now we need copy some bits from the submodule into our document root so that WordPress can work as expected.

[gist id=”2b8b123f1a7079c250cc” file=”initial-wordpress-config.sh”]

In this setup, I like to version my wp-config.php because I usually run a local dev version of my WordPress instance in addition to the production version. There is more on this topic below in Pre-Install Security and Config.

You will also need to edit index.php to load the WordPress resources correctly. The best way to see this is via the commit diff for index.php.

Manage Themes and Plugins in Git

In order to be able to version themes and plugins in our Git repository, we need to copy the wp-content/ directory from the submodule:

[gist id=”2b8b123f1a7079c250cc” file=”manage-themes-and-plugins-in-git.sh”]

Cleaning up Themes and Plugins

It’s always a good idea to delete themes and plugins that you won’t use. To support this, I usually delete the default plugins and all but the most recent theme.

[gist id=”2b8b123f1a7079c250cc” file=”cleaning-up-themes-and-plugins.sh”]

Pre-Install Security and Config

There is some data in wp-config.php that is common to both installations and having it versioned makes keeping everything in sync much easier. However, I do not want my keys, salts, or database credentials in version control. To support this setup I create a separate environment.php file which contains the bits I don’t want in version control and import that into my wp-config.php.


You can see see the updated wp-config.php file and a sample environment.php file both in the GitHub repo.

As you can see in the wp-config.php we also need to setup appropriate URLs and Directories to support referencing resources in the submodule.

Database Prefix

The final step I like to take before the WordPress setup is to change the default database prefix. I like to follow the pattern of wp_XXXXXXXX_ where I still start with wp_ but then add in a random 8 character string generated by Random.org.

I keep this in the wp-config.php file rather than environment.php so that it is easier to keep my local dev and production in sync and refresh my local database from production when necessary.

In Conclusion

In my next post, I’ll go over post-installation security and plugins that we can use for keeping everything more secure.