Capistrano is a Ruby-based server automaton and deployment tool that is primarily designed to deploy Ruby (on Rails) applications, but also works really well for deploying Node.js applications because of its sensible defaults.

I'm not going to explain exactly how Capistrano works, instead I'm just going to describe my Capistrano configuration for a simple Node.js application. To get started with Capistrano read through the documentation on their website and follow the instructions to set up Capistrano in your project.

Assuming you are using a single stage (e.g. 'production'), set up your stage file (probably config/deploy/production.rb ) so that your server is responsible for all app roles:

# config/deploy/production.rb server 'my.server.com', user: 'me', roles: %w{app db web}

Then set up your config/deploy.rb file to look something like this:

# config/deploy.rb # config valid only for current version of Capistrano lock '3.4.0' set :application, 'my-application' set :repo_url, 'git@github.com:me/my-application.git' set :deploy_to, "/home/me/Applications/#{fetch :application}" # Link node_modules so it is shared between deploys. # If you also have a log folder, or other folders that # should be shared, add them here set :linked_dirs, %w( node_modules ) namespace :deploy do desc 'Copy upstart script' task :upstart do on roles(:app) do within release_path do sudo :cp, "etc/#{fetch :application}.upstart.conf", "/etc/init/#{fetch :application}.conf" end end end desc 'Restart application' task :restart do on roles(:app) do sudo :service, fetch(:application), 'restart' end end desc 'Install node modules' task :install_node_modules do on roles(:app) do within release_path do execute :npm, 'install', '-s' end end end after :updated, :install_node_modules after :updated, :upstart after :publishing, :restart end

First, we specify that this configuration only works with the latest Capistrano version, which isn't strictly true, but is a safe default.

Next, we specify the name of the application, the location of the git repository and where we want to deploy to.

We instruct Capistrano to link node_modules between deploys. This means it will put node_modules in the shared folder in the root of the deployment location and symlink it in to each deployed version so that all the modules don't have to be reinstalled every time we deploy.

The deploy block describes the various tasks we want to run, and when to run them, you can also run them individually e.g. cap production deploy:restart .

Our deploy:upstart copies an upstart script from the deployed application directory into the correct place on the system using sudo for elevated permissions. This would require passwordless-sudo to be enabled. Capistrano has more information on how to do this.

copies an upstart script from the deployed application directory into the correct place on the system using sudo for elevated permissions. This would require passwordless-sudo to be enabled. Capistrano has more information on how to do this. deploy:restart is pretty self explanatory, using sudo again to restart the service with upstart.

is pretty self explanatory, using sudo again to restart the service with upstart. deploy:install_node_modules does exactly what you would expect; runs npm on the server in the deployed directory.

Finally, we set up the deploy hooks to ensure these tasks run at the appropriate time.

Of course you would also need a web server (e.g. Nginx) to proxy to this Node.js application. You could keep the configuration for Nginx in the repository as well and copy it to the appropriate place much like the upstart script in the example above. You could even reload Nginx as part of the restart task.

This is the simplest configuration that can work, but it is easy to add additional functionality on top of this base configuration. Some examples of configurations I have used:

Locally building & uploading a set of static files

desc 'Locally build the static site' task :build_static do run_locally do within 'static' do execute :grunt, 'build' end end end desc 'Upload the static site' task :upload_static do on roles(:app) do upload! 'static/dist', release_path.join('static'), recursive: true end end before :check, :build_static after :updated, :upload_static

Ensuring a file is present on the server

desc 'Ensure a file is present' task :ensure_file do on roles(:app) do unless test '[ -f /srv/file ]' error " Missing file in /srv directory." exit 1 end end end before :check, :ensure_file

Capistrano is a powerful, if slightly retro, tool. I hope this post is useful when you're next deploying a Node.js application :) let me know in the comments if you have a different preferred deployment method!