Blue-Green deployments are a strategy to achieve zero downtime during deployments, improving system reliability. Here, we'll demonstrate how to set up a Blue-Green deployment system for a Next.js application using PM2, Nginx, and GitHub.
What's Blue-Green Deployment?
Blue-Green deployments involve having two production environments: Blue (currently live) and Green (new version). When a new release is ready, it's deployed to the inactive environment (Green). Once tested and verified, traffic is switched over, making Green the active environment. This allows immediate rollback capabilities and minimizes downtime.
Setting it Up for Next.js
1. Two Environments: Set up two directories, representing Blue and Green environments: nextjs-blue and nextjs-green.
2. Nginx Configuration: Configure Nginx to switch between Blue and Green by adjusting the proxy_pass directive.
3. PM2 Configuration: Use PM2, a process manager for Node.js, to manage both environments. Each environment should have its distinct port.
4. Deployment Script: Create a bash script to automate the deployment process. This script will:
- Pull the latest code from GitHub.
- Build the Next.js application.
- Start or restart the application using PM2.
- Check the application's health.
- Switch Nginx to the newly deployed environment.
- Stop the old PM2 process.
#!/bin/bash
# Configuration
BLUE_DIR="/path/to/nextjs-blue"
GREEN_DIR="/path/to/nextjs-green"
GREEN_PORT="3001" # Port on which Green runs
BLUE_PORT="3000" # Port on which Blue runs
NGINX_CONFIG="/etc/nginx/sites-available/nextjs"
GITHUB_REPO="https://github.com/your-username/your-repo.git"
# Determine which environment is currently running (Blue or Green)
CURRENT_PORT=$(grep -oP 'proxy_pass http://localhost:\K\d+' $NGINX_CONFIG)
# Determine the old PM2 process name
OLD_NAME=""
TARGET_DIR=""
if [ "$CURRENT_PORT" == "$BLUE_PORT" ]; then
TARGET_DIR=$GREEN_DIR
TARGET_PORT=$GREEN_PORT
OLD_NAME=$(basename $GREEN_DIR)
else
TARGET_DIR=$BLUE_DIR
TARGET_PORT=$BLUE_PORT
OLD_NAME=$(basename $BLUE_DIR)
fi
# Step 1: Pull from GitHub into target environment
echo "Pulling latest code into target environment ($TARGET_DIR)..."
cd $TARGET_DIR
git pull $GITHUB_REPO
# Step 2: Yarn Build for target version
echo "Building target environment..."
yarn install
yarn build
# Start/Restart the target environment using PM2
TARGET_NAME=$(basename $TARGET_DIR)
pm2 stop $TARGET_NAME
pm2 delete $TARGET_NAME
pm2 start yarn --name "$TARGET_NAME" -- start -p $TARGET_PORT || pm2 restart $TARGET_NAME
echo "Stopping old environment ($OLD_NAME)..."
pm2 stop $OLD_NAME
pm2 delete $OLD_NAME
pm2 save
# Allow a few seconds for the server to start
sleep 5
# Step 3: Check if target version index page returns 200
echo "Checking target environment health..."
STATUS_CODE=$(curl -o /dev/null -s -w "%{http_code}" http://localhost:$TARGET_PORT)
if [ "$STATUS_CODE" -ne 200 ]; then
echo "Target environment health check failed with status code: $STATUS_CODE"
exit 1
fi
# Step 4: Switch Nginx to target environment
echo "Switching Nginx to target environment..."
sed -i "s/proxy_pass http:\/\/localhost:[0-9]*;/proxy_pass http:\/\/localhost:$TARGET_PORT;/" $NGINX_CONFIG
nginx -s reload
echo "Deployment complete. Target environment ($TARGET_NAME) is now live!"
5. Automate with GitHub: Use GitHub Actions or webhooks to automate the deployment when changes are merged into the main branch.
Security Considerations:
- Always validate incoming webhooks.
- Use HTTPS for webhook endpoints.
- Protect sensitive operations with authentication or IP whitelisting.
Wrapping Up:
Blue-Green deployments offer a systematic approach to releasing software, enhancing uptime, and enabling quick rollbacks. This guide provides a foundation for Next.js applications, but the principles can be extended to other systems. Always test in a staging environment before moving to production.