Skip to main content
GitHub Actions
CHAPTER 08

Deploying Applications with GitHub Actions

Updated: May 15, 2026
25 min read

# CHAPTER 8

Deploying Applications with GitHub Actions

1. Introduction

We have built our code and tested it rigorously. Now comes the moment of truth: the "Continuous Deployment" (CD) phase. This is where GitHub Actions takes the verified code and pushes it to the live production server, making it available to the public. Deployments are inherently risky; if a file transfers incorrectly, the website goes down. In this chapter, we will explore the mechanisms GitHub Actions uses to deploy applications, focusing on traditional SSH workflows, and understand how to strictly separate the CI (Testing) logic from the CD (Deployment) logic using multiple jobs.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the transition from Continuous Integration to Continuous Deployment.
  • Configure multiple jobs within a single workflow using the needs keyword.
  • Utilize Marketplace Actions to securely transfer files via SSH/SCP.
  • Execute remote commands (like restarting web servers) on a production machine.
  • Understand the risks associated with deployment automation.

3. Beginner-Friendly Explanation

Imagine a space launch.
  • Job 1 (The CI Check): The engineers run system checks on the rocket. Is the fuel tank sealed? (Unit Tests). If the checks fail, the launch is aborted.
  • The Dependency (needs:): The Launch sequence CANNOT start until the System Checks are 100% complete and successful.
  • Job 2 (The CD Deployment): The checks passed. The launch sequence begins. The rocket is sent to space (Code is sent to the production server).

4. Structuring a CI/CD Pipeline (The needs Keyword)

In Chapter 2, we learned that multiple jobs run in *parallel* by default. If Job 1 is "Test" and Job 2 is "Deploy", we DO NOT want them running at the same time. If the test fails, the code might have already been deployed! We fix this using the needs keyword.
yaml
1234567891011
jobs:
  test-the-code:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

  deploy-to-prod:
    runs-on: ubuntu-latest
    needs: test-the-code # STOP! Wait for 'test-the-code' to turn green first!
    steps:
      - run: echo "Deploying..."

If test-the-code fails, the deploy-to-prod job is automatically cancelled.

5. Traditional Deployments (SSH/SCP)

If you are deploying a traditional web application (like PHP/Laravel or Node.js) to a standard Linux server (like a DigitalOcean Droplet or AWS EC2), you must securely transfer the files over the internet. We do not write complex SSH Bash scripts from scratch. We use pre-built Marketplace actions, such as appleboy/scp-action for transferring files, and appleboy/ssh-action for running remote server commands.

6. Mini Project: Deploy PHP App Automatically

Let's build a CD job that copies files to a server and restarts the web service. *(Note: We will learn how to handle the secret passwords in Chapter 10. For now, we will use placeholders).*

Step-by-Step Pipeline Concept:

yaml
12345678910111213141516171819202122232425262728293031323334353637383940
name: Production Deployment
on:
  push:
    branches:
      - main # Only deploy when code is pushed directly to main

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "Running tests..."

  deploy:
    runs-on: ubuntu-latest
    needs: test # Ensure tests pass first!
    
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        
      - name: Copy files via SCP to Production Server
        uses: appleboy/scp-action@master
        with:
          host: 192.168.1.50 # Server IP
          username: admin # Server Username
          key: ${{ secrets.SSH_PRIVATE_KEY }} # We will cover Secrets later!
          source: "."
          target: "/var/www/html/myapp"

      - name: Execute remote SSH commands
        uses: appleboy/ssh-action@master
        with:
          host: 192.168.1.50
          username: admin
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/html/myapp
            composer install --no-dev
            sudo systemctl reload nginx

7. Real-World Scenarios

A junior developer set up a GitHub Actions workflow with a test job and a deploy job, but forgot to include the needs: test line under the deploy job. They pushed buggy code that broke the website's checkout page. The test job correctly failed with a red X. However, because the deploy job was running in parallel, it successfully copied the buggy code to the production server at the exact same time. The site went down. Adding a single line of YAML (needs: test) established the correct sequential dependency, saving the company from future outages.

8. Best Practices

  • Deployment Environments: GitHub has a feature called "Environments." In your repository settings, you can create an environment named production. You can add "Protection Rules" to this environment, such as requiring a specific manager to click "Approve" before the deployment job is allowed to run.

9. Security Recommendations

  • Least Privilege SSH: The SSH Key used by GitHub Actions to log into your production server should not belong to the root user. Create a dedicated Linux user (e.g., github_deployer) on your server that only has permission to write to the /var/www/html directory. If your GitHub account is compromised, the attacker only gains limited access to the server, rather than total root control.

10. Troubleshooting Tips

  • Rsync vs SCP: The scp-action copies every single file, every single time. If your project has 10,000 files, this takes a very long time and causes downtime. For larger projects, look into actions that use rsync, which only transfers files that have changed since the last deployment.

11. Exercises

  1. 1. What is the purpose of the needs keyword when defining multiple jobs in a workflow?
  1. 2. Why must we use a Marketplace Action (like appleboy/ssh-action) to execute remote commands, instead of just using standard shell commands on the runner?

12. FAQs

Q: Can I deploy to AWS, Azure, or Google Cloud? A: Yes! All major cloud providers have official actions in the GitHub Marketplace designed to deploy specifically to their services (e.g., aws-actions/amazon-ecs-deploy-task-definition). The core concept remains the same: Authenticate, then Deploy.

13. Interview Questions

  • Q: Architect a GitHub Actions workflow containing 'Build', 'Test', and 'Deploy' jobs. Explain the YAML configuration required to ensure they execute sequentially, and detail what happens if the 'Test' job fails.
  • Q: Describe the security risks of performing direct SSH deployments from GitHub Actions. How would you mitigate the risk of exposing the production server to unauthorized access?

14. Summary

In Chapter 8, we completed the Continuous Delivery lifecycle by pushing code out of the GitHub cloud and onto our live production servers. We mastered the needs keyword, learning how to chain jobs sequentially to ensure that deployment only occurs if all prior quality checks pass. We utilized robust, community-driven Marketplace actions to securely transfer files and execute remote server restarts, transforming GitHub Actions from an internal testing tool into a formidable, end-to-end deployment engine.

15. Next Chapter Recommendation

We used someone else's code (the appleboy actions) to do our deployment. What exactly is the GitHub Marketplace, and how do we use it safely? Proceed to Chapter 9: Using Marketplace Actions.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·