f in x
Automated Deploy to Staging and Production — A CD Pipeline That Won't Lose You Customers
> cd .. / HUB_EDITORIALE
Sviluppo di siti web

Automated Deploy to Staging and Production — A CD Pipeline That Won't Lose You Customers

[2026-06-26] Author: Ing. Calogero Bono
Zenithby Meteora Web Il sistema operativo della tua attività. Social, clienti, prenotazioni e fatture in un'unica piattaforma. Palestre, barber, professionisti. Scopri Zenith Demo gratis · senza carta

Have you ever spent an hour doing manual FTP deployments, forgot to exclude the debug folder, and found the site down? Or pushed an update straight to production without testing on staging and broke the contact form? We at Meteora Web see this every day in projects that come to us. Manual deployment is the hidden cost that eats margins: lost time, human errors, unhappy customers. A well-built CD pipeline fixes it all. In this guide we show you how to build one for staging and production, with working code and solid economic logic.

Why an Automated Deploy is an Investment, Not an Expense?

If you think like an accountant — and we come from accounting — you know every repetitive operation must be measured in €/hour. Take a manual deploy: prepare files, FTP, overwrite, test, possibly rollback. A two-developer team can waste 2-3 hours per week. Over 50 weeks, that’s 100–150 hours a year. At €50/hour average cost, you’re throwing away €5,000–7,500 annually. A CD pipeline costs a few hours of initial setup and then runs on its own. ROI is immediate.

Moreover, human error costs dearly: wrong .env credentials, leftover development folders, untested plugin updates. We saw it on a clothing e-commerce: a manual deploy overwrote the size database. Recovery: 4 extra hours, and the store was offline. With a CD pipeline, that doesn't happen.

Sponsored Protocol

How Does a CD Pipeline for Staging and Production Work?

A Continuous Delivery pipeline automates code delivery from repository to target environment. Typical flow: push to branch → automatic tests (CI) → build → deploy to staging → (optional) acceptance tests → deploy to production with manual approval. We use GitHub Actions, but the concept applies to GitLab CI, Bitbucket Pipelines, Jenkins. Key is separating staging (testing environment) from production (live environment) with gates that prevent publishing without control.

Branch Structure

We work with a simple model: main branch is always what’s in production. develop branch is for ongoing work. Feature branches branch off develop and merge back. Then a release branch is created from develop for staging deploy. Finally, the release branch merges into main for production. This prevents unstable code from reaching clients.

Environments and Environment Variables

Each environment has its own config file (.env.staging, .env.production) with real database connections, API keys, etc. Never save these variables in the repository. We manage them via GitHub Secrets or an external vault. The pipeline injects variables at deploy time. This way code is identical across environments; only configuration changes.

How to Set Up an Automatic Deploy Flow to Staging Without Risks?

Let's start with a concrete scenario: a PHP/Laravel app (but principles apply to Node, Python, custom WordPress). You have a Linux VPS with SSH access, and you want every push to develop to trigger a staging deploy.

Sponsored Protocol

SSH Deploy Script (basic)

We use a bash script executed by the pipeline. Here's an example for Laravel using rsync to transfer only changed files, reducing time:

#!/bin/bash
# deploy-staging.sh

SERVER_USER="deploy"
SERVER_HOST="staging.example.com"
SERVER_PATH="/var/www/staging"

# Transfer via rsync with exclusions
echo "Transferring files..."
rsync -avz --delete \
    --exclude '.git' \
    --exclude '.env' \
    --exclude 'node_modules' \
    --exclude 'storage' \
    --exclude 'vendor' \
    -e ssh ./ $SERVER_USER@$SERVER_HOST:$SERVER_PATH

# Post-deploy commands (via SSH)
echo "Running post-deploy commands..."
ssh $SERVER_USER@$SERVER_HOST "
    cd $SERVER_PATH &&
    composer install --no-dev --optimize-autoloader &&
    php artisan migrate --force &&
    php artisan config:cache &&
    php artisan route:cache &&
    php artisan view:cache &&
    php artisan queue:restart
"
echo "Deploy to staging complete."

Note: composer install and artisan migrate are executed server-side. The pipeline needs SSH access with private key (stored as secret).

GitHub Actions Workflow for Staging

Create file .github/workflows/deploy-staging.yml:

Sponsored Protocol

name: Deploy to Staging

on:
  push:
    branches: [ develop ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H ${{ secrets.STAGING_HOST }} >> ~/.ssh/known_hosts
      - name: Run deploy script
        run: |
          chmod +x ./scripts/deploy-staging.sh
          ./scripts/deploy-staging.sh
        env:
          SERVER_USER: ${{ secrets.STAGING_USER }}
          SERVER_HOST: ${{ secrets.STAGING_HOST }}
          SERVER_PATH: ${{ secrets.STAGING_PATH }}

Every time you push to develop, the pipeline runs rsync and post-deploy. Zero manual intervention.

What Measures for a Safe and Impact-Free Production Deploy?

Production is a different story: you can't afford downtime. And you can't trigger a deploy without human approval. Here's how we structure CD for production with approval gates and zero-downtime.

Production Workflow with Manual Approval

We use workflow_run or environment with required reviewers. In GitHub Actions, create an environment “production” with branch main and enable “Required reviewers”. Then in the workflow:

name: Deploy to Production

on:
  push:
    branches: [ main ]

jobs:
  approve:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - run: echo "Approval obtained"
  deploy:
    needs: approve
    runs-on: ubuntu-latest
    steps:
      # SSH setup and rsync with similar script, but production version

Thus, when a push to main happens, the “approve” job waits for a reviewer (e.g., lead developer) to greenlight. Only then does the deploy start. No accidental deployments.

Sponsored Protocol

Zero-Downtime Deploy for Web Applications

To avoid the site going offline during deploy, we use a symbolic link technique. On the server, keep two directories: /var/www/production/releases/20240501-v1.2.3 (new release) and a symlink /var/www/production/current -> releases/20240501-v1.2.3. The pipeline:

  1. Uploads the new release to a timestamped temporary directory.
  2. Runs composer install, artisan migrate, etc.
  3. If everything’s fine, updates the symlink: ln -sfn releases/new current
  4. Cleans up old releases (e.g., keep last 3).

The web server (Nginx/Apache) always points to current. The switch is instantaneous. Existing users keep seeing the old version until next page load, but there’s no downtime.

Instant Rollback

If the deploy causes errors, rollback is a simple symlink change. You can even automate it with a separate on-demand workflow. Just keep a script that points current to the previous release. We integrate it with a Slack /deploy:rollback command.

Sponsored Protocol

What to Do Now — Concrete Actions

You don’t need to implement everything in one day. Here are immediate steps to start:

  1. Identify your environments: Do you have at least one staging server? If not, create one (even a €5/month VPS is better than nothing).
  2. Set up SSH key-based auth: Generate a key pair, add the public key to the server, save the private key as a secret in your repository (e.g., SSH_PRIVATE_KEY).
  3. Create a basic deploy script (rsync) for staging, like the one above. Test it manually before integrating into the pipeline.
  4. Set up a CI/CD workflow triggered on the develop branch. Use GitHub Actions or GitLab CI.
  5. Add manual approval for production and zero-downtime switch. Not immediately required, but plan to implement before the next major release.
  6. Monitor deployments: integrate notifications on Slack/Telegram to know if everything went well or if there was a failure.

If you want to dive deeper into the entire DevOps cycle, read our pillar guide on DevOps and CI/CD Pipeline.

And remember: a well-oiled automated deploy doesn't just save you time and money — it turns your team into a reliable machine. No more sleepless nights over a bad deploy. Your clients will feel it — and see it in the revenue.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ Read Full Dossier ]

> METEORA_WEB // DIGITAL AGENCY

We build the digital presence your business deserves.

Websites, social media, online advertising, e-commerce and high-performance hosting, engineered with method by computer engineers in Sciacca, for all of Italy.

> MW_JOURNAL

> READ_ALL()