DEV Community

Cover image for "From 30-Minute Manual Deployments to 5-Minute Automation: My CI/CD Journey"
Kuldeep Singh
Kuldeep Singh

Posted on

"From 30-Minute Manual Deployments to 5-Minute Automation: My CI/CD Journey"

my-app/ ├── .github/ │ └── workflows/ │ └── deploy.yml ├── public/ ├── src/ ├── package.json ├── next.config.js ├── README.md └── ...

Code

Step 2: Creating the GitHub Actions Workflow

Here's the workflow file I created:


yaml
name: Deploy to EC2

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Deploy to Server
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.PRIVATE_SSH_KEY }}
          script: |
            echo "🎉 Starting Birthday App deployment..."

            # Create app directory if it doesn't exist
            mkdir -p ~/birthday-app
            cd ~/birthday-app

            # Clone or update the repository
            if [ -d ".git" ]; then
              echo "📦 Updating existing repository..."
              git pull origin main
            else
              echo "📦 Cloning repository..."
              git clone https://github.com/Kuldeep2602/CI_CD.git .
            fi

            # Navigate to the app directory
            cd my-app

            # Install dependencies
            echo "📋 Installing dependencies..."
            npm install

            # Build the application
            echo "🔨 Building Next.js application..."
            npm run build

            # Install PM2 if not already installed
            if ! command -v pm2 &> /dev/null; then
              echo "📦 Installing PM2..."
              npm install -g pm2
            fi

            # Stop existing app if running
            pm2 stop birthday-app 2>/dev/null || true

            # Start the application with PM2
            echo "🚀 Starting Birthday App with PM2..."
            pm2 start npm --name "birthday-app" -- start
            pm2 save

            # Show status
            pm2 status
            echo "✅ Birthday App deployment completed successfully!"
Step 3: Setting Up GitHub Secrets
To securely handle sensitive information, I added these secrets to my GitHub repository:

Go to your Repository → Settings → Secrets and variables → Actions
Add the following secrets:
HOST: The public IP of your EC2 instance (e.g., 13.60.232.88)
USERNAME: The SSH username (e.g., ubuntu)
PRIVATE_SSH_KEY: Your private SSH key (the content of your .pem file)
Step 4: Setting Up the EC2 Instance
I prepared my EC2 instance with:

bash
# Update system packages
sudo apt update && sudo apt upgrade -y

# Install Node.js and npm
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs

# Install Git
sudo apt install -y git

# Install PM2 globally
sudo npm install -g pm2

# Set up SSH authorized_keys for GitHub Actions
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Add your public key to ~/.ssh/authorized_keys
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
Step 5: Using Ngrok for Public Access
To make my application publicly accessible without a domain:

bash
# Install Ngrok
wget https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-linux-amd64.tgz
tar xvzf ngrok-v3-stable-linux-amd64.tgz
sudo mv ngrok /usr/local/bin/

# Configure Ngrok
ngrok config add-authtoken YOUR_AUTH_TOKEN

# Start Ngrok to expose your Next.js app (running on port 3000)
ngrok http 3000
The Results
After implementing this CI/CD pipeline, I achieved:

83% faster deployments: From 30 minutes to just 5 minutes
Zero deployment errors: Eliminated the 20% failure rate
Zero downtime: PM2 ensures smooth application restarts
Confidence in deploying: No more fear of breaking the production environment
Challenges I Faced
SSH Key Format: Initially, GitHub Actions couldn't connect to my EC2 instance because of incorrect SSH key formatting. I had to ensure the key was properly formatted with proper line breaks.

IP Address Mismatch: I mistakenly used an old IP address in my GitHub secrets, causing connection timeouts. Always double-check your host IP when configuring secrets!

PM2 Persistence: I learned that without pm2 save, the process list wasn't persisted across server restarts.

Lessons Learned
Automate Everything: Every manual step is an opportunity for error
Security First: Use secrets for sensitive information
Zero-Downtime Deployments: PM2 is invaluable for Node.js applications
Testing is Essential: Next step is to integrate automated testing
Next Steps
Add automated testing to the workflow
Set up monitoring and alerts
Implement a staging environment
Replace Ngrok with a proper domain and HTTPS
Conclusion
Building this CI/CD pipeline has transformed my development workflow and significantly improved productivity. The ability to push code and have it automatically deployed within minutes is incredibly powerful.

Have you implemented CI/CD for your projects? What tools and approaches did you use? Let me know in the comments!

You can check out the live application here: https://86d2-13-60-232-88.ngrok-free.app/

GitHub Repo: https://github.com/Kuldeep2602/CI_CD

Code

This blog post is now correctly formatted for DEV.to with:

1. Proper frontmatter metadata
2. Correctly formatted directory structure using code blocks
3. All code samples properly formatted with language specification
4. Current date (June 28, 2025) included
5. Your GitHub username (Kuldeep2602) incorporated
6. All content sections maintained with proper headings
7. Helpful tips and command examples throughout

Enter fullscreen mode Exit fullscreen mode

Top comments (0)