Markus Hedlund

Developer / Photographer

Contact / GitHub / Instagram

Deploy Node.js on Ubuntu with Git post-receive hook

Use git push to deploy your code, and nvm to use seperate node versions per project.


Step 1. Setup in the user account

SSH in as myproject


Create the bare git repo that you will push to for deployment.

mkdir ~/myproject.git
cd ~/myproject.git
git init --bare
nano hooks/post-receive

Paste the script below.


set -e

export NVM_DIR="$HOME/.nvm"
. "$NVM_DIR/"

NEW_DIR="$HOME/app/`date +%Y-%m-%d-%H.%M.%S`"

mkdir -p $REPO_DIR

git --work-tree="$REPO_DIR" --git-dir="$GIT_DIR" checkout -f
git --work-tree="$REPO_DIR" checkout-index -a --prefix="$NEW_DIR/"

cd "$NEW_DIR" && nvm i && npm i --production

rm -f "$CURRENT_DIR"

sudo restart myproject

What's happening:

  1. Initiate environment.
  2. Config variables.
  3. Make a copy of the project to a new directory.
  4. Build the project.
  5. Relink to the latest version and restart the service.

Now set execute rights on the script.

chmod u+x hooks/post-receive

Step 2. Setup as root

Switch to root.

sudo su -

Create the service description file by editing /etc/init/myproject.conf.

start on runlevel [2345]

env LANG=en_US.UTF-8
env PORT=7777

setuid myproject
setgid myproject

chdir /home/myproject/app/current

  NODE_VERSION=`cat /home/myproject/app/current/.nvmrc`
  exec /home/myproject/.nvm/versions/node/v$NODE_VERSION/bin/node .
end script
  1. What runlevel this service will start on.
  2. Environment variables.
  3. What user and group id we will run as.
  4. Make sure the service respawns automatically if it crashes.
  5. cd into the latest deployment and start with the correct version of Node.

Add visudo entry with command visudo and add this to the bottom.

myproject ALL=NOPASSWD: /sbin/restart myproject, /sbin/start myproject, /sbin/stop myproject

Step 3. Test deployment

On you local machine, add the remote and push to it. prod in the example below is the name of the deployment environment, prod is short for produciton.

git remote add prod
git push prod master

Note: The first time it will fail to restart the service because it isn't running. I recommend that you uncomment that line the first time.

Possible improvements