69

I'm currently developing my WordPress locally, committing my code to GitHub with Git and then SSHing into my server and doing a "git pull" to update my code. Is this a good option for code deployment onto a WordPress site (I obviously have root level access to my server in this case.) I know of things like Capistrano, but would that be overkill for deployment to a WordPress site? How can I make the most of Git/GitHub in this case?

2
  • I use deployhq.com and really like the features they offer. It's a paid service but I find the price to be reasonable. If you happen to host with WP Engine (I do) they recently rolled out a git push feature: git.wpengine.com.
    – dwenaus
    Commented Feb 5, 2013 at 9:46
  • How do you handle this use case? You have done some customisations on WordPress, WordPress themes folder, and did some settings change in a plugin (that plugin stores the settings in db). Like this, we did many such plugins installs, and settings changes in localhost, now without repeating the settings changes of plugin how can I setup in hosting server. The biggest challenge is your hosting server has 1000 blog posts that are live. without loosing the challenge how will you deploy your localhost wordpress on the live server. Commented Jun 14, 2022 at 16:58

4 Answers 4

64

I use git for this and find it works really well. A few suggestions:

  • Add your uploads directory (wp-content/uploads) directory to your .gitignore file.
  • Run a web server and database server on your development system so you can test changes locally before pushing them to production.
  • Keep your database connection settings consistent beween dev and prod, or add wp-config.php to your .gitignore file to prevent your development wordpress settings overwriting your production ones.
  • Avoid updating plugins on your production system using the admin interface of Wordpress - as at best, your git copy will overwrite any plugins you update as soon as you push/checkout, at worst you'll get conflicts. Do your updates using the the admin interface on your development system, commit, push and checkout in production.
  • Consider adding a git post-receive hook to checkout your updates automatically into the directory you use to publish wordpress via your web server (e.g. /var/www). This allows you to only check out the files themselves, avoiding any git metadata finding it's way into your web server's document root, and also means you can add any permission changes into the post-receive hook so your permissions stay consistent every time. An example is included below:

    #!/bin/sh
    unset GIT_INDEX_FILE
    # the directory your web server serves wordpress from 
    export GIT_WORK_TREE=/var/www/example.com/
    # the local directory where your remote git repository sites
    export GIT_DIR=/home/git/repos/example.com.git/
    # below user is for debain - you want the user and group your webserver uses
    sudo git checkout -f
    sudo chown -R www-data:www-data $GIT_WORK_TREE
    sudo chmod -R 755 $GIT_WORK_TREE
    sudo chmod 600 $GIT_WORK_TREE/wp-config.php
    sudo chmod -R 775 $GIT_WORK_TREE/wp-content
    
6
  • Is the backtick appearing after unset GIT_INDEX_FILE a typo? Commented Jan 29, 2013 at 22:44
  • James has pretty much summed up my worfklow, except I only add the theme files to the git repo once I have the staging/test/production site established. Also I totally recommend using a post-receive hook on the remote server, saves logging in and doing a git pull etc.
    – davemac
    Commented Feb 4, 2013 at 7:54
  • That, along with SSH aliases means I can push to the live theme repo using 'git push live' etc
    – davemac
    Commented Feb 4, 2013 at 8:00
  • 1
    I'm not familiar with the plugin updating process in wordpress but what happens if the plugin update makes changes to the database? How will those local changes get pushed to the production server?
    – User
    Commented Jun 13, 2014 at 5:21
  • @User that would vary from plugin to plugin. Core wordpress does schema version checks, so if you update Wordpress without using the built in updater, it will do the DB updates seperately. My advice would be if you are using any plugins that write to the DB, that you check the admin area of Wordpress, as schema updates are usually handled there regardless of how you update the plugin code.
    – user25611
    Commented Jun 13, 2014 at 6:30
22

I would highly recommend setting up Capistrano - it's a little bit of upfront work the first time, but after that you can easily use it for new setups.

The main advantages are

  • being able to deploy from your desktop. It may not sound like much, but ssh-ing into the your remote server, and doing a git pull is still a pain in the ass.
  • easy rollback to a previous version if you need to
  • able to do cool things like setup deployment to staging/production environments.

I'm adding a set of capistrano scripts to show you how I set things up.

Capfile

require 'railsless-deploy'
load 'config/deploy'`

deploy.rb

set :stages, %w(production staging local)
set :default_stage, "staging"
require 'capistrano/ext/multistage'

set :application, "" # your application name - used to set directory name

set :scm, :git
set :repository, "" # use the ssh repo access line you get from the provider eg [email protected]:name/repo.git
set :deploy_to, "/var/www/#{application}" #this is the root site folder on the remote server
set :deploy_via, :remote_cache # get directly from repo
set :copy_exclude, [".git", ".DS_Store", ".gitignore", ".gitmodules", "wp-config.php"]

# makes capistrano ask for sudo password or other remote inputs
default_run_options[:pty] = true

namespace :tasks do
    task :fix_links  do
        run "ln -nfs #{shared_path}/uploads #{release_path}/wp-content/uploads"
        run "ln -nfs #{shared_path}/wp-config.php #{release_path}/wp-config.php"
      run "ln -nfs #{shared_path}/blogs.dir #{release_path}/wp-content/blogs.dir"
      run "ln -nfs #{shared_path}/.htaccess #{release_path}/.htaccess"
      run "sudo chown -R www-data.www-data #{release_path}/"
    end
end

after "deploy", "tasks:fix_links"

and finally, a sample environment file (if you use the multistage gem, then you can have one of these for each stage of your environment, eg local, staging, production)

config/local.rb

server "", :app  #hostname
set :branch, 'develop' #choose branch to deploy
set :use_sudo, false #don't use sudo

set :deploy_to, "/var/www/#{application}" #overwrite default path to deploy to

These files might not work without tweaking, and you'll need some basic Capistrano knowledge, but hopefully will help some people.

This was the first tutorial I used that got me going with Capistrano and WordPress: http://theme.fm/2011/08/tutorial-deploying-wordpress-with-capistrano-2082/

4
  • 2
    If you use git post-receive hooks, they negate the need to ssh in to the remote server and do a git pull
    – davemac
    Commented Feb 4, 2013 at 7:57
  • git post-receive hook is the way to go! Commented May 14, 2013 at 1:07
  • 3
    @dirt the problem with the post-receive hook is that unless you've got a decent CI infrastructure in place, one incorrect merge can bring down your whole site. The likelihood of this increases if you're working on a project with multiple devs who have commit access to your repo. That's why I, personally, like to deploy via capistrano instead, but I can see why others might not worry about it so much.
    – anu
    Commented May 14, 2013 at 6:53
  • 1
    You use a bare git repo so the merge issue is not relevant
    – davemac
    Commented Aug 2, 2013 at 12:07
9

I actually did a WordCamp presentation on this topic. Rather than repeat myself, here's a screencast of it and here's a very simple deployment script to accompany what I discussed.

In short, I use GitHub to host the repo, and use a webhook to deploy changes based on the git ref. This allows you to use Vincent Driessen's git branching model and opens you up to having unlimited webheads, staging servers, testing servers, etc., all with automated deployment. I also cover keeping wp-config.php under version control while maintaining separate dev/production versions (by renaming the files and symlinking).

0
4

I know this question is a little older however as I've not seen this as answer here, I'd like to share what I normally do for single-site git based setups and deployments and it's working really well, also with working from multiple devices, locations and with multiple developers (all having their own local repos they operate in as it is common for git).

I can warm-heartedly suggest the following setup:

It is also outlined in (if you need a second resource to wrap your head around it):

It basically works (with at least three repos) by:

  1. putting the website on the live-host under git,
  2. create a new bare git repository on the live host.
  3. And then fork from the bare repository to your local development git repo(s).

When the work is done you push against the remote bare repo you've cloned from. The bare repo has hooks to sync with the live repo (in the codes above called prime).

As Wordpress specific settings in the repo I have this .gitignore:

# uploads are data, excluded from source tree
wp-content/uploads/

The rest incl. the plugin and theme configuration I keep under version/configuration control. This allows me to easily track changes and review code before using it live. I can also more easily merge against remote trees with my own changes. That is especially useful against the Wordpress core which is available on Github.

This works pretty well for most of my Wordpress needs. The bare repo prevents you from pushing conflicting changes. It also syncs to a remote copy first before updating the live-site. That means, updating the live-site is normally pretty fast. Because of the hooks you can even call Wordpress update hooks afterwards if you like.

If have not experimented how much this can be improved with Github hooks, but I normally do not need them as the code is under local version control, not Github.

To set such a system up for the first time, you should take some time to evaluate if you've got all the tools available on your remote host:

  • SSH access
  • GIT
  • A private directory you can put files and sub-directories in (e.g. for your bare git repo)

The setup-time for the first time should be possible within one two hours incl. the whole environment and you first publish push.

Depending on your host, you might also want to shield the .git directory from web-access. Here is some example .htaccess code that even does so having Wordpress placed inside a sub-directory, which leaves space in the repo not published online (useful):

Options -Indexes

# fix trailing slash for .git / make it disappear + .gitignore and similar files.
RedirectMatch 404 ^/\.git(.*)$

# mask 403 on .ht* as 404
<Files ~ "^\.ht">
  Order Deny,Allow
  Allow from all
  Satisfy All
  Redirect 404 /
</Files>

RewriteEngine On
RewriteBase /

# map everything into public and set environment var
# to tag the request being valid
RewriteCond %{ENV:REDIRECT_sitealias} !set
RewriteRule ^(.*)$ /public/$1 [E=sitealias:set,L]

In short, everything not inside the public directory is not online. Inside the public directory can be the wordpress codebase for example, for the .htaccess there you need then:

RewriteEngine On
# mask as 404 if directly accessed
RewriteCond %{ENV:REDIRECT_sitealias} !set
RewriteRule .* - [L,R=404]

This prevents direct access to public. Part of this .htaccess-foo you can find outlined here: Requests to .htaccess should return 404 instead of 403. For the environment variables you need to test if that works in your environment. Also you need to decide if you put that under version control or not.

If you have more control on the hosting, you can do more stuff here (and differently / more optimized), the examples above are targeted for typical shared-hosting environments (that offer GIT, some users say you can easily install it your own as well, I normally ask my hosters to provide such because I prefer if they take care that's what I pay them for).

On the negative side, this has some of the common problems also outlined in the other answers. One thing I'm not proud of but what works is to give the development host a change to it's host file to have the database server point to the development copy. So you can keep one database configuration. Not really cool esp. because of the credentials.

Automatic Backups

However I normally don't care much here but instead have daily backups run on the remote systems which are incrementally which themselves are stored in another remote location then. That's easy and cheap and allows you to restore both the Wordpress install as well as the file-uploads, the database and the git repo. Also for my backup commands I might not be perfectly alright, but those work for me:

mysql: mysqldump --host=%s -u %s --password=%s %s| gzip > %s
git  : git gc
       git bundle
files: tar --force-local -czf %s %s

What I do suggest here is that you keep the processes around your Wordpress installation out of Wordpress. They need to run on a specific system, so you normally do not have them inside the application (e.g. application can go down but you need to have these continue to work).

Enabled for Teamwork

Another nice benefit is that you site is enabled for team-work already. Thanks to the additional bare repo you can't do much wrong and you can even share remote branches apart from a master or live branch with your colleagues.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.