← Back to Own Your Stack

Sample Chapter from Own Your Stack

Chapter 7: Rsync Deployment

Rsync copies files from your workstation to the server. It's fast, reliable, and you control exactly what gets deployed. This chapter covers the essentials: how rsync works, what to exclude, automating deploys with a script, and handling post-deployment tasks.

7.1 How Rsync Works

Rsync compares source and destination, then copies only what changed. First deploy copies everything. Subsequent deploys are fast because most files haven't changed.

Basic syntax:

rsync [options] source/ destination/

The trailing slash matters:

Always use source/ with the trailing slash for deploying.

7.2 Essential Rsync Options

rsync -avz --delete ./ deploy@server:/var/www/myapp/

-a (archive): Preserves permissions, timestamps, symlinks. What you want for deployments.

-v (verbose): Shows what's being transferred. Helpful for debugging.

-z (compress): Compresses data during transfer. Faster over slow connections.

--delete: Removes files on server that don't exist locally. Keeps the deployment clean. Without this, deleted files linger forever.

Other Useful Options

--dry-run: Shows what would happen without doing it. Test before deploying.

rsync -avz --delete --dry-run ./ server:/var/www/myapp/

-P (progress): Shows transfer progress. Nice for large uploads.

-e: Specify SSH options (non-standard port, specific key).

rsync -avz -e "ssh -p 2222" ./ server:/var/www/myapp/

7.3 Exclude Patterns

You don't want to upload everything. Development files, IDE configs, and local artifacts should stay on your workstation.

Using --exclude

rsync -avz --delete \
    --exclude='.git' \
    --exclude='.idea' \
    --exclude='node_modules' \
    --exclude='.DS_Store' \
    ./ server:/var/www/myapp/

Using an Exclude File

For complex patterns, put them in a file. Create rsync-excludes.txt:

# Version control
.git
.gitignore
.gitattributes

# IDE and editor
.idea
.vscode
*.swp
*~

# OS files
.DS_Store
Thumbs.db

# Development
node_modules
tests
phpunit.xml
phpunit.xml.dist
.phpunit.result.cache

# Documentation (unless serving it)
README.md
CHANGELOG.md
docs

# Server-side files (don't overwrite these)
config/config.php
storage/logs/*
storage/cache/*
storage/uploads/*
public/uploads/*

Use it with:

rsync -avz --delete --exclude-from='rsync-excludes.txt' ./ server:/var/www/myapp/

7.4 The Deploy Script

Wrap rsync and post-deploy commands in a script. Create deploy.sh in your project root:

#!/bin/bash
set -e

# Configuration
SERVER="myserver"  # SSH host from ~/.ssh/config
REMOTE_PATH="/var/www/myapp"
EXCLUDE_FILE="rsync-excludes.txt"
PHP_SERVICE="php8.3-fpm"

echo "Deploying to $SERVER..."

# Sync files
rsync -avz --delete \
    --exclude-from="$EXCLUDE_FILE" \
    ./ "$SERVER:$REMOTE_PATH/"

# Run post-deploy commands on server
ssh "$SERVER" bash -c "'
    cd $REMOTE_PATH

    # Install/update dependencies
    composer install --no-dev --optimize-autoloader --no-interaction

    # Fix permissions
    sudo chown -R deploy:www-data .
    chmod -R 775 storage/

    # Run database migrations
    php scripts/migrate.php

    # Reload PHP-FPM to clear opcache
    sudo systemctl reload $PHP_SERVICE

    echo \"Deploy complete on server\"
'"

echo "Done!"

Make it executable:

chmod +x deploy.sh

Deploy with:

./deploy.sh

7.5 Why Reload PHP-FPM?

PHP caches compiled scripts in memory (opcache) for performance. After rsync updates files on disk, PHP-FPM workers still have old bytecode cached.

In production, opcache.revalidate_freq is typically 0 - PHP never checks if files changed. Without a reload, PHP serves old code indefinitely.

systemctl reload gracefully restarts workers. Existing requests finish, new workers start with empty opcache. No connections dropped.

7.6 Post-Deploy Steps Explained

The deploy script runs several commands on the server after syncing files:

Composer Install

composer install --no-dev --optimize-autoloader --no-interaction

Run this after every deploy in case composer.lock changed.

Permissions

sudo chown -R deploy:www-data .
chmod -R 775 storage/

Ensures web server can read files and write to storage directories.

7.7 Deployment Checklist

First-Time Setup

Before Each Deploy

Deploy

This is just one of 31 chapters. The complete guide covers everything from initial server setup to monitoring, backups, and disaster recovery.

Get the Full Guide - $59