Björn Brynjúlfur

Automatic deployment to VPS with git

For new projects, I set up automatic deployment to an Ubuntu VPS via git. I use DigitalOcean for hosting and they have a tutorial for this. However, it is 8 years old and the commands provided now give me errors.

To make this process faster for new projects in the future, I am writing a shortened and modified version of the tutorial here. It will work with any VPS hosting provider:

1. Initialize a bare repository

Connect to the VPS via SSH (I have a shell alias for this command):

ssh [username]@[VPS IP address]

Then initialize a bare git repository:

cd /var
cd repo
mkdir [project-name].git
cd [project-name].git
git init --bare

Aside: This assumes you store repositories in /var/repo. In hindsight, I wish I had stored them in ~/repo, as they are specific to me as a user, but it would be too much work to change this for every project.

2. Set up a post-receive hook

Assuming you are still in /var/repo/[project-name].git on the VPS:

cd hooks
nano post-receive

Paste in the following and save:

#!/bin/sh
git --work-tree=/home/[username]/docs/[project-name] --git-dir=/var/repo/[project-name].git checkout -f

Finally, add execution permission to the file:

chmod +x post-receive

This will update your project files on the server, assuming you store them in ~/docs.

You now have two options to restart your app automatically:

  1. Use a process manager to restart the app automatically when file changes in the project directory are detected
  2. Add a command at the bottom of the post-receive file to restart the app

[Optional] More automation:

I also add these lines to the post-receive file for some projects:

cd /home/[username]/docs/[project-name]/server
npm install --silent
npm run build
pm2 reload [project-name]

This is NodeJS and PM2 specific. It does the following:

  1. Installs packages that I added on my development machine, as I skip them in .gitignore.
  2. Runs a build process. For my latest project, it generates an optimized CSS file using the TailwindCSS CLI tool
  3. Restarts the app. Here, I use PM2 in cluster mode to run two instances of the app. The reload command restarts them in succession, ensuring zero downtime on deployment.

This is just what I could think of for my first project after I realized this was possible. Git hooks are powerful!

3. Configure a local repository

Leave the VPS

exit

Initialize a repository on your local machine:

cd [root of your project]
git init

Add a remote path (the name live can be anything):

git remote add live ssh://[username]@[VPS IP address]/var/repo/[project-name].git

4. Push and deploy

git add .
git commit -m "Initial commit"
git push live master

That's it - your project is deployed. Now you can push your changes from the local machine, and they will automatically be deployed on the server.