Grunt Deployment over SSH with Git
Grunt.js is a task runner that comes with various plugins for compiling, building, formatting, etc. within your project. I covered some of the basics of using this tool in my article about using Grunt Watch and LiveReload for real-time compilation.
I recently setup a simple deployment process using Grunt, so I thought I’d share the details. I found a couple deployment-related Grunt plugins out there, but they didn’t really suit my needs. Instead, I opted to simply use the grunt-ssh plugin to connect to my server and run the necessary commands to update, build and restart my application. Let’s take a look at a simplified Gruntfile.coffee.
module.exports = (grunt) ->
grunt.initConfig
sshconfig:
someserver:
host: 'someserver.com'
username: 'someuser'
agent: process.env.SSH_AUTH_SOCK
agentForward: true
sshexec:
deploy:
command: [
'cd /home/someuser/app'
'git pull origin master'
'npm install'
'forever stop server.js'
'forever start server.js'
'forever list'
].join(' && ')
options:
config: 'someserver'
grunt.registerTask 'deploy', [
'sshexec:deploy'
]
grunt.loadNpmTasks('grunt-ssh')
When the task above is executed, by running grunt deploy
, a number of things
will happen. Grunt will SSH into someserver.com
, with the user someuser
.
It’ll then move into the /home/someuser/app
directory, pull down the latest
master from the git repo, run an npm install
(which, in my case, also triggers
a build task), then restart the application using the
forever package.
Most of the commands (and definitely the host/user names) will need to be
customized on your end to suite your needs. For instance, if this isn’t a
Node.js project, you may not be using npm install
or forever
. You can
replace those commands with the proper commands to build and restart your
application. This example also assumes that you already have your Git repo setup
in /home/someuser/app
. You may have it somewhere else, or you may not be using
Git at all, and instead need to pull down files using some other process.
The entire array specified under command
can be updated to suite your needs.
Because I’m combining the commands using &&
, if any one of them fails, the
deployment process will stop.
Notes on Authentication
The example above makes a couple assumptions about authentication which may not apply in your case, so I want to offer an alternative.
In the code above you’ll see two lines like this:
agent: process.env.SSH_AUTH_SOCK
agentForward: true
This is telling the SSH process to login into the server using my active set of
private keys. For this to work, I must have the server configured to accept my
private key. In short, this means I need to have mykey_rsa
in the ~/.ssh
directory of my local machine, and the matching mykey_rsa.pub
loaded into
~/.ssh/authorized_keys
on the server. If you’re unfamiliar with this setup, or
can’t make it work, you can change the agent lines above to use a password
instead, like this:
password: 'PASSWORD-GOES-HERE'
Be careful with this approach though because you’ll be saving your plain text password in your Gruntfile.
Conclusion
While perhaps not the most ideal candidate for deployment, Grunt can accomplish quite a bit. The example above is very simple, but the solution I’m currently using extends this code to include deployments to multiple servers, uploads to S3, and more. If you’re shopping around for a simple way to deploy your application, give the code above a shot.