
Next JS deployment with Devops and PM2
Quick write-up for simple NextJS deployments using Azure Devops and PM2
Build pipeline
# azure-pipelines.yml
trigger:
- main
- develop
pool:
name: linux
steps:
- task: CopyFiles@2
inputs:
Contents: |
**/*
!.git/**/*
targetFolder: "$(Build.ArtifactStagingDirectory)"
cleanTargetFolder: true # Optional
overWrite: true # Optional
- task: NodeTool@0
inputs:
versionSpec: "16.x"
displayName: "Install Node.js"
- script: |
npm install
npm run build
displayName: "npm install and build"
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: "$(Build.ArtifactStagingDirectory)"
includeRootFolder: false
archiveType: "tar"
archiveFile: "$(Build.ArtifactStagingDirectory)/$(Build.BuildId).tar"
replaceExistingArchive: true
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: "$(Build.ArtifactStagingDirectory)/$(Build.BuildId).tar"
artifactName: drop
Configure server
Run pm2 and deployment scripts as an unprivileged user, such as “nodejs”. groupadd nodejs; useradd -G nodejs nodejs
Set up deploy scripts
# /usr/local/bin/deploy-myapp-prod.sh
#!/bin/bash
cd /var/www/myapp-prod && \
tar xf /opt/deploy/$1 -C /var/www/myapp-prod && \
npm install && npm run build && \
pm2 restart myapp
# /usr/local/bin/deploy-myapp-staging.sh
#!/bin/bash
cd /var/www/myapp-staging && \
tar xf /opt/deploy/$1 -C /var/www/myapp-staging && \
npm install && npm run build && \
pm2 restart myapp-staging
Remember to chmod a+x /usr/local/bin/deploy-myapp-staging.sh /usr/local/bin/deploy-myapp-prod.sh
Install PM2
su - nodejs
npm install pm2@latest -g
# Manually copy the source code to /var/www/myapp-prod and /var/www/myapp-staging so that we can set up the apps in PM2
# run prod app on port 3000
cd /var/www/myapp-prod
pm2 start npm --name "myapp-prod" -- start
# run staging app on port 3001
cd /var/www/myapp-staging
pm2 start npm --name "myapp-staging" -- start -- -p 3001
Set up service connection
Azure Devops: Project settings -> Service connections
- New service connection
- SSH
- Configure hostname etc, make sure to use SSH keys for authentication. Log in as the unprivileged user.
Set up release pipelines
Each push to develop branch should initiate a deployment to the staging environment.
Azure Devops: Pipelines -> Releases -> New release pipeline
- Start with an “Empty job”
- Add an artifact
- Source type: build
- Project: your project
- Source: your build pipeline
- Stages
- Start with an “Empty job”
- Name the pipeline “Staging”
- Continuous deployment trigger
- Enabled
- Build branch filters
- Include Build branch: develop
- Tasks:
- Securely copy files to the remote machine
- SSH service connection: your service connection
- Source folder: $(System.DefaultWorkingDirectory)/[_myapp]/drop
- Target folder: /opt/deploy
- Run shell commands on remote machine
/usr/local/bin/deploy-myapp-staging.sh $(Build.BuildId).tar
- Securely copy files to the remote machine
Each push to main branch should initiate a deployment to the production environment.
Add a new release pipeline called “Production”.
- Include Build branch: main
- Shell command:
/usr/local/bin/deploy-myapp-prod.sh $(Build.BuildId).tar