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?
-
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.– dwenausCommented 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.– indianwebdevilCommented Jun 14, 2022 at 16:58
4 Answers
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
-
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.– davemacCommented 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– davemacCommented Feb 4, 2013 at 8:00
-
1I'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?– UserCommented 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.– user25611Commented Jun 13, 2014 at 6:30
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/
-
2If you use git post-receive hooks, they negate the need to ssh in to the remote server and do a git pull– davemacCommented Feb 4, 2013 at 7:57
-
-
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.– anuCommented May 14, 2013 at 6:53
-
1
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).
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:
- putting the website on the live-host under git,
- create a new bare git repository on the live host.
- 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.