Skip to content

Instantly share code, notes, and snippets.

@learncodeacademy
Last active January 7, 2024 11:58
Show Gist options
  • Save learncodeacademy/35045e64d2bbe6eb14f9 to your computer and use it in GitHub Desktop.
Save learncodeacademy/35045e64d2bbe6eb14f9 to your computer and use it in GitHub Desktop.
Deploy Node.js Apps with Flightplan

##Setup your server (this would ideally be done with automated provisioning)

  • add a deploy user with password-less ssh see this gist
  • install forever npm install -g forever

##Install flightplan

  • npm install -g flightplan
  • in your project folder npm install flightplan --save-dev
  • create a flightplan.js file
var plan = require('flightplan');

var appName = 'node-app';
var username = 'deploy';
var startFile = 'bin/www';

var tmpDir = appName+'-' + new Date().getTime();

// configuration
plan.target('staging', [
  {
    host: '104.131.93.214',
    username: username,
    agent: process.env.SSH_AUTH_SOCK
  }
]);

plan.target('production', [
  {
    host: '104.131.93.215',
    username: username,
    agent: process.env.SSH_AUTH_SOCK
  },
//add in another server if you have more than one
// {
//   host: '104.131.93.216',
//   username: username,
//   agent: process.env.SSH_AUTH_SOCK
// }
]);

// run commands on localhost
plan.local(function(local) {
  // uncomment these if you need to run a build on your machine first
  // local.log('Run build');
  // local.exec('gulp build');

  local.log('Copy files to remote hosts');
  var filesToCopy = local.exec('git ls-files', {silent: true});
  // rsync files to all the destination's hosts
  local.transfer(filesToCopy, '/tmp/' + tmpDir);
});

// run commands on remote hosts (destinations)
plan.remote(function(remote) {
  remote.log('Move folder to root');
  remote.sudo('cp -R /tmp/' + tmpDir + ' ~', {user: username});
  remote.rm('-rf /tmp/' + tmpDir);

  remote.log('Install dependencies');
  remote.sudo('npm --production --prefix ~/' + tmpDir + ' install ~/' + tmpDir, {user: username});

  remote.log('Reload application');
  remote.sudo('ln -snf ~/' + tmpDir + ' ~/'+appName, {user: username});
  remote.exec('forever stop ~/'+appName+'/'+startFile, {failsafe: true});
  remote.exec('forever start ~/'+appName+'/'+startFile);
});

##Deploy!

  • fly staging or fly production

##Take it to the next level Run your node app as a system service so it runs after server reboots

@benstuijts
Copy link

Hi, great video and tutorial. Could you please create an other with the scenario of using flightplan from a Window's machine? Since Windows doesn't use the rsync command...

Copy link

ghost commented Aug 7, 2016

Thanks for the tutorial..! 👍
By using the package.json file for the name and the main file you can make the script even more generic!

const plan = require('flightplan');
const pkg = require('./package.json');

const username = 'deploy';
const tmpDir = pkg.name + '-' + new Date().getTime();

// configuration
plan.target('production', [
    {
        host: 'myHost',
        username: username,
        agent: process.env.SSH_AUTH_SOCK
    },
]);

// run commands on localhost
plan.local((local) => {
    local.log('Copy files to remote hosts');
    var filesToCopy = local.exec('git ls-files', { silent: true });
    // rsync files to all the destination's hosts
    local.transfer(filesToCopy, '/tmp/' + tmpDir);
});

// run commands on remote hosts (destinations)
plan.remote((remote) => {
    remote.log('Move folder to root');
    remote.sudo('cp -R /tmp/' + tmpDir + ' ~', { user: username });
    remote.rm('-rf /tmp/' + tmpDir);

    remote.log('Install dependencies');
    remote.sudo('npm --production --prefix ~/' + tmpDir + ' install ~/' + tmpDir, { user: username });

    remote.log('Reload application');
    remote.sudo('ln -snf ~/' + tmpDir + ' ~/' + pkg.name, { user: username });
});

@paradoxall
Copy link

if you are using express change ;)

  remote.exec('forever stop ~/'+appName+'/'+startFile, {failsafe: true});
  remote.exec('forever start ~/'+appName+'/'+startFile);

by

    remote.exec('cd ~/'+ appName  + '&&' + 'forever start ./bin/www', {failsafe: true});
    remote.exec('cd ~/'+ appName  + '&&' + 'forever stop ./bin/www');

@vishnutmohan
Copy link

vishnutmohan commented Jan 9, 2018

I am always getting error while running flightplan. But when running the script directly is working. Any idea?

$ echo 'npm --production --prefix ~/node-app-1515514102251 install ~/node-app-1515514102251' | sudo -u ubuntu -i bash
bash: line 1: npm: command not found
● failed (127)

Copy link

ghost commented Jul 31, 2018

how to solved this
Permission denied (publickey).
localhost > rsync: connection unexpectedly closed (0 bytes received so far) [sender]

@hintonbradley
Copy link

Hey! Good tutorial - thanks for making this.
All goes well until the very last step. When I attempt to push to production (fly production), I get an the following error:

✈ Running default:production
✈ Executing local task
localhost Copy files to remote hosts
localhost $ git ls-files
localhost ● ok
● Empty file list passed to transfer()

Anyone have any ideas? FYI: I'm running on a mac.

@gbrits
Copy link

gbrits commented May 26, 2019

You have to perform a git add . for the first git ls-files to have tracked files. So first git add . then fly production

@gbrits
Copy link

gbrits commented May 26, 2019

For anyone running into authentication issues, try explicitly declaring your privateKey: 'path/to/the/.ssh/id_rsa', in your staging/production configs.

@ronikiko
Copy link

ronikiko commented Jun 2, 2019

hello all
i get this error why?
localhost ● ok
✈ Local task finished after 16 s
✈ Connecting to 'XXX.XXX.XX.XX'
● Error connecting to 'XXX.XXX.XXX.XX': All configured authentication methods failed

@SumitGA
Copy link

SumitGA commented Oct 31, 2019

I was working on my Vagrant Box and got these issues

localhost ● ok
✈ Local task finished after 16 s
✈ Connecting to 'XXX.XXX.XX.XX'
● Error connecting to 'XXX.XXX.XXX.XX': All configured authentication methods failed

The issue was with ssh connection, so I went up to my vagrant config file and added
config.ssh.forward_agent = true

Then I was able to run fly production and deploy to my vagrant box. Also, make sure to check your production server has node and forever installed correctly or else it will not work.

@kennylugo
Copy link

kennylugo commented Nov 17, 2019

You have to perform a git add . for the first git ls-files to have tracked files. So first git add . then fly production

This worked for me, thanks! Error I was having before was: localhost > rsync: link_stat failed: No such file or directory (2)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment