← Blog · Tutorials

Getting Started with GitHub Actions: Automate Your Website Deployments

April 17, 2026

Getting Started with GitHub Actions: Automate Your Website Deployments

Every time you push code, you SSH into your server, pull the latest changes, restart services, and hope nothing breaks. Sound familiar? There's a better way.

GitHub Actions lets you automate your entire deployment pipeline — from running tests to deploying code — every time you push to your repository. No more manual deployments, no more forgotten steps, no more "it works on my machine" problems.

Here's how to set it up from scratch.

What Are GitHub Actions?

GitHub Actions is a CI/CD (Continuous Integration / Continuous Deployment) platform built directly into GitHub. You define workflows in YAML files, and GitHub runs them automatically based on triggers like pushing code, opening pull requests, or on a schedule.

Push to main → Run tests → Build → Deploy to server 

The best part? It's free for public repositories and includes 2,000 minutes per month for private repos on the free tier.

Your First Deployment Workflow

Let's build a real workflow that deploys a website to a VPS whenever you push to the main branch.

Step 1: Create the Workflow File

In your repository, create .github/workflows/deploy.yml:

name: Deploy to Production  on:   push:     branches: [main]  jobs:   deploy:     runs-on: ubuntu-latest     steps:       - name: Checkout code         uses: actions/checkout@v4        - name: Deploy to server         uses: appleboy/ssh-action@v1         with:           host: ${{ secrets.SERVER_HOST }}           username: ${{ secrets.SERVER_USER }}           key: ${{ secrets.SSH_PRIVATE_KEY }}           script: |             cd /var/www/mysite             git pull origin main             npm install --production             npm run build             pm2 restart myapp 

Step 2: Add Repository Secrets

Never hardcode credentials. Go to your GitHub repo → Settings → Secrets and variables → Actions, and add:

  • SERVER_HOST — Your server's IP address (e.g., 203.0.113.50)
  • SERVER_USER — SSH username (e.g., deploy)
  • SSH_PRIVATE_KEY — Your private SSH key

To generate a deployment key:

ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/deploy_key 

Add the public key to your server's ~/.ssh/authorized_keys and paste the private key into the GitHub secret.

Step 3: Push and Watch

Commit the workflow file and push to main. Go to the "Actions" tab in your repo to watch the deployment run in real time.

Adding Tests Before Deployment

Deploying untested code is risky. Add a test step that runs before deployment:

name: Test and Deploy  on:   push:     branches: [main]  jobs:   test:     runs-on: ubuntu-latest     steps:       - uses: actions/checkout@v4              - name: Setup Node.js         uses: actions/setup-node@v4         with:           node-version: '20'           cache: 'npm'              - name: Install dependencies         run: npm ci              - name: Run tests         run: npm test    deploy:     needs: test     runs-on: ubuntu-latest     steps:       - uses: actions/checkout@v4              - name: Deploy to server         uses: appleboy/ssh-action@v1         with:           host: ${{ secrets.SERVER_HOST }}           username: ${{ secrets.SERVER_USER }}           key: ${{ secrets.SSH_PRIVATE_KEY }}           script: |             cd /var/www/mysite             git pull origin main             npm install --production             npm run build             pm2 restart myapp 

The needs: test directive ensures deployment only happens after all tests pass.

WordPress Deployment Workflow

For WordPress sites, the workflow looks slightly different:

name: Deploy WordPress Theme  on:   push:     branches: [main]  jobs:   deploy:     runs-on: ubuntu-latest     steps:       - uses: actions/checkout@v4        - name: Deploy theme via rsync         uses: burnett01/rsync-deployments@6.0.0         with:           switches: -avzr --delete --exclude='.git' --exclude='.github'           path: wp-content/themes/mytheme/           remote_path: /var/www/mysite/wp-content/themes/mytheme/           remote_host: ${{ secrets.SERVER_HOST }}           remote_user: ${{ secrets.SERVER_USER }}           remote_key: ${{ secrets.SSH_PRIVATE_KEY }} 

Rsync only transfers changed files, making deployments fast and efficient.

Laravel Deployment

Laravel projects need a few extra steps:

name: Deploy Laravel  on:   push:     branches: [main]  jobs:   deploy:     runs-on: ubuntu-latest     steps:       - uses: actions/checkout@v4        - name: Deploy to server         uses: appleboy/ssh-action@v1         with:           host: ${{ secrets.SERVER_HOST }}           username: ${{ secrets.SERVER_USER }}           key: ${{ secrets.SSH_PRIVATE_KEY }}           script: |             cd /var/www/mylaravel             git pull origin main             composer install --no-dev --optimize-autoloader             php artisan migrate --force             php artisan config:cache             php artisan route:cache             php artisan view:cache             sudo systemctl reload php8.2-fpm 

Deployment Notifications

Get notified when deployments succeed or fail. Add a Slack or Discord notification step:

      - name: Notify on success         if: success()         run: |           curl -X POST "${{ secrets.DISCORD_WEBHOOK }}" \\             -H "Content-Type: application/json" \\             -d '{"content": "✅ Deployment successful: ${{ github.repository }} (${{ github.sha }})"}'        - name: Notify on failure         if: failure()         run: |           curl -X POST "${{ secrets.DISCORD_WEBHOOK }}" \\             -H "Content-Type: application/json" \\             -d '{"content": "❌ Deployment FAILED: ${{ github.repository }} — check Actions tab"}' 

Best Practices

Use Environment Protection Rules

For production deployments, enable environment protection in GitHub:

  1. Go to Settings → Environments → New environment → "production"
  2. Add required reviewers (optional — someone must approve before deploy)
  3. Restrict to main branch only

Keep Secrets Secure

  • Never echo secrets in logs
  • Rotate SSH keys periodically
  • Use deploy-specific keys with limited permissions
  • Consider using OIDC for cloud providers instead of long-lived keys

Handle Rollbacks

Add a manual rollback workflow:

name: Rollback  on:   workflow_dispatch:     inputs:       commit_sha:         description: 'Commit SHA to rollback to'         required: true  jobs:   rollback:     runs-on: ubuntu-latest     steps:       - name: Rollback deployment         uses: appleboy/ssh-action@v1         with:           host: ${{ secrets.SERVER_HOST }}           username: ${{ secrets.SERVER_USER }}           key: ${{ secrets.SSH_PRIVATE_KEY }}           script: |             cd /var/www/mysite             git fetch origin             git checkout ${{ github.event.inputs.commit_sha }}             npm install --production             npm run build             pm2 restart myapp 

Trigger this manually from the Actions tab when you need to revert a bad deploy.

Common Pitfalls to Avoid

🚩 No test step — Always test before deploying. A broken deployment takes your site down.

🚩 Root SSH access — Create a dedicated deploy user with limited permissions.

🚩 No timeout — Add timeout-minutes: 10 to your jobs to prevent hung deployments.

🚩 Deploying on every push — Only deploy from your main branch. Use pull requests for code review.

🚩 No notification on failure — If you don't know a deployment failed, you can't fix it.

Automate Your Deployments with DeployBase

GitHub Actions handles the CI/CD pipeline, but you still need reliable infrastructure to deploy to. At DeployBase, our VPS plans come with full SSH access, pre-installed Git, and the performance your applications need. Starting at $5.99/month with NVMe SSD storage, automated backups, and email support.

Pair GitHub Actions with DeployBase hosting and you get a professional deployment pipeline that rivals setups costing ten times as much.

Get your VPS at DeployBase → — reliable hosting for automated deployments.