How to deploy NPM projects without downtime in Laravel Forge

July 3, 2023

Zero Downtime Deployments with Laravel Forge

MetricsWave is hosted in AWS and leverages Laravel Forge to simplify code deployment without the need to individually configure each machine.

Laravel Forge is a great tool that enables you to quickly configure your Laravel Server and deploy code simply by pushing it to your Git repository, but the default Deployment Script can be improved.

Also, in this case, we are using Laravel Forge to deploy a site that is not build with Laravel. We are deploying a simple React application, so we need to make changes to make it to works.

Update your Nginx Configuration file

The first thing you need to change is the Nginx configuration file. This is not a PHP site, so you need to make some changes. Something like this should be more than enough.

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name app.metricswave.com;
    server_tokens off;
    root /home/forge/app.metricswave.com/build;

    # FORGE SSL (DO NOT REMOVE!)
    ssl_certificate /etc/nginx/ssl/app.metricswave.com/1809605/server.crt;
    ssl_certificate_key /etc/nginx/ssl/app.metricswave.com/1809605/server.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers XXXXXXXXXXXX;
    ssl_prefer_server_ciphers off;
    ssl_dhparam /etc/nginx/dhparams.pem;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm;

    charset utf-8;

    # FORGE CONFIG (DO NOT REMOVE!)
    include forge-conf/app.metricswave.com/server/*;

    location / {
        try_files $uri /index.html;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/app.metricswave.com-error.log error;

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/app.metricswave.com/after/*;

Update Laravel Forge Deploy Script

In this case, we also need to update the deployment script, because we are not deploying a PHP site, but also, we are going to make deployments safer with no downtime.

# Configuration
DEPLOY_FOLDER_DATE=$(date '+%Y%m%d%H%M%S')
WEBSITE_FOLDER="app.metricswave.com"
GIT_REPO="git@github.com:MetricsWave/app.git"
METRICS_WAVE_EVENT="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"

##
## Deployment process
##
echo 'Create new deploy folder…'
echo "Folder: /home/forge/${WEBSITE_FOLDER}_deployments/${DEPLOY_FOLDER_DATE}"
mkdir -p /home/forge/app.metricswave.com_deployments/$DEPLOY_FOLDER_DATE

echo 'Building app in deployment folder…'
cd /home/forge/$WEBSITE_FOLDER_deployments/$DEPLOY_FOLDER_DATE
git clone $GIT_REPO .
git pull origin $FORGE_SITE_BRANCH

echo "NPM install and build…"
npm install
npm run build

echo 'Replacing current app with deployment folder…'
rm -rf /home/forge/$WEBSITE_FOLDER
ln -s /home/forge/$WEBSITE_FOLDER_deployments/$DEPLOY_FOLDER_DATE /home/forge/$WEBSITE_FOLDER

cd /home/forge/$WEBSITE_FOLDER

( flock -w 10 9 || exit 1
    echo 'Restarting FPM...'; sudo -S service $FORGE_PHP_FPM reload ) 9>/tmp/fpmlock

# Remove previous deploys
cd /home/forge/$WEBSITE_FOLDER_deployments
find . -maxdepth 1 -mindepth 1 -type d -printf "%T+ %f\0" | sort -z | head -z -n -1 | cut -z -d' ' -f 2- | xargs -0 rm -rf &

# Notify deployment
cd /home/forge/$WEBSITE_FOLDER
BODY='{"version":"'$(git log --pretty=format:'%h' -n 1)'", "message":"'$(git log --pretty=format:'%s' -n 1)'","author":"'$(git log --pretty=format:'%an' -n 1)'", "service":"Application"}'
curl -X POST https://metricswave.com/webhooks/$METRICS_WAVE_EVENT \
  -H "Content-Type: application/json" \
-H "Accept: application/json" \
-d "$BODY"

The process is super simple:

  1. We are creating another folder where we are going to prepare our site to be deployed. We are going to pull a fresh copy of our code and run npm install and build there.
  2. When everything is ready, we are going to replace the current production site with the new build.
  3. After this, we just deployed the new site to production, but we are going to remove the previous build to avoid using disk space.
  4. The last step is to send a notification to our team using MetricsWave.

← Go back to the blog

Choose the plan
that fits your needs

Start for free, and upgrade your account at any moment.

All plans include:

  • 100% data ownership
  • Forever data retention
  • No cookie banner required
  • GDPR law compliance
  • Unlimited support
  • Cancel at any time
  • All features available