Skip to content

Instantly share code, notes, and snippets.

@learncodeacademy
Last active January 7, 2024 11:58
Star You must be signed in to star a gist
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

@aconital
Copy link

aconital commented Jun 2, 2015

I get same error :-/ localhost > 'rsync' is not recognized as an internal or external command,

@ashe540
Copy link

ashe540 commented Jun 21, 2015

rsync is a linux command, so windows doesn't recognize it. You can give it a shot with cwRsync (https://www.itefix.net/cwrsync) if you're brave enough.

Copy link

ghost commented Aug 17, 2015

When installing locally your video shows "npm install fly --save-dev". Above you say "npm install flightplan --save-dev". Which one is it?.... seems to be flightplan thanks. Great tutorials! Keep it up

@gartenfeld
Copy link

Where do you get the socket from?

@gartenfeld
Copy link

Why sync the files to a tmp directory first then move them to home?

@andredelgado
Copy link

If I use system services, does the process restart if it crashes?

@marcioamr
Copy link

On Windows I've the error bellow:

C:\Program Files\Git>npm install -g flightplan
\

> fibers@1.0.9 install C:\Users\marcior\AppData\Roaming\npm\node_modules\flightplan\node_modules\fibers
> node build.js || nodejs build.js

-
C:\Users\marcior\AppData\Roaming\npm\node_modules\flightplan\node_modules\fibers>node "C:\Program Files\nodejs\node_modules\npm\bin\node-gyp-bin\\..\.
.\node_modules\node-gyp\bin\node-gyp.js" rebuild --release
gyp ERR! configure error
gyp ERR! stack Error: spawn ENOENT
 ERR! stack     at errnoException (child_process.js:1001:11)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (child_process.js:792:34)
gyp ERR! System Windows_NT 6.1.7601
ERR! command "node" "C:\\Program Files\\nodejs\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js" "rebuild" "--release"
gyp ERR! cwd C:\Users\marcior\AppData\Roaming\npm\node_modules\flightplan\node_modules\fibers
gyp ERR! node -v v0.10.32
gyp ERR! node-gyp -v v1.0.1
gyp ERR! not ok
Build failed
'nodejs' não é reconhecido como um comando interno
ou externo, um programa operável ou um arquivo em lotes.
npm ERR! fibers@1.0.9 install: `node build.js || nodejs build.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the fibers@1.0.9 install script.
npm ERR! This is most likely a problem with the fibers package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node build.js || nodejs build.js
npm ERR! You can get their info via:
npm ERR!     npm owner ls fibers
npm ERR! There is likely additional logging output above.

npm ERR! System Windows_NT 6.1.7601
npm ERR! command "C:\\Program Files\\nodejs\\\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "install" "-g" "flightplan"
npm ERR! cwd C:\Program Files\Git
npm ERR! node -v v0.10.32
npm ERR! npm -v 1.4.28
npm ERR! code ELIFECYCLE
npm ERR! not ok code 0

@danielvaughan
Copy link

Yes in the video it says to do npm install fly --save-dev locally but it seems to need to be npm install flightplan --save-dev as above

@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