The backend for my chat application is built using NestJS and TypeScript Firestore for data persistence and WebSockets for real-time communication. This setup ensures that users can find and connect with participants seamlessly, receive instant message notifications when online, and access new conversations upon re-entering the app after being offline. I deployed it on a DigitalOcean droplet and added continuous integration and deployment managed via GitHub Actions for smooth updates and maintenance.
Basically to setup the Node.js app on the Digital Ocean I did the following
My goal was to automate the update process of the app after pushing changes to the main branch, eliminating the need for manual pulls, rebuilds, and PM2 restarts. To achieve this, I used GitHub Actions to run a script that handles these tasks automatically.
The script, named deploy.sh, requires environment variables, which I added to GitHub's "Repository secrets" under "Actions secrets and variables."
#!/bin/bash
# Check if required environment variables are set
if [ -z "$REMOTE_USER" ] || [ -z "$REMOTE_HOST" ] || [ -z "$REMOTE_DIR" ] || [ -z "$PM2_PROCESS_NAME" ]; then
echo "One or more environment variables are missing."
exit 1
fi
# Use the environment variables to perform operations
ssh ${REMOTE_USER}@${REMOTE_HOST} << EOF
cd ${REMOTE_DIR}
pm2 stop ${PM2_PROCESS_NAME}
git pull origin main
npm run build
pm2 start ${PM2_PROCESS_NAME}
EOF
Then I created a workflow to run this script and called it deploy.yml.
name: Deploy
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up SSH
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
run: |
# Ensure .ssh directory exists
mkdir -p ~/.ssh
# Save SSH private key
echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# Start the SSH agent and add the private key
eval $(ssh-agent -s)
ssh-add ~/.ssh/id_rsa
# Add remote host to known_hosts
ssh-keyscan -H $REMOTE_HOST >> ~/.ssh/known_hosts
- name: Grant execute permission to deploy.sh
run: chmod +x ./deploy.sh
- name: Run deployment script
env:
REMOTE_USER: ${{ secrets.REMOTE_USER }}
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_DIR: ${{ secrets.REMOTE_DIR }}
PM2_PROCESS_NAME: ${{ secrets.PM2_PROCESS_NAME }}
run: ./deploy.sh
So that's it—after I pushed my changes, I could see them deployed. Here is the GitHub repo that uses these files chat-backend-app