Skip to content

Instantly share code, notes, and snippets.

@mujahidi
Last active November 5, 2025 14:55
Show Gist options
  • Select an option

  • Save mujahidi/6ce85b821db96040e44d67dab09c8c52 to your computer and use it in GitHub Desktop.

Select an option

Save mujahidi/6ce85b821db96040e44d67dab09c8c52 to your computer and use it in GitHub Desktop.
Local Development with Automated Remote Server Sync - Complete Setup

Complete setup for local web development with automated file synchronization to remote server. This configuration allows you to:

  • Develop locally with full IDE features and build tools
  • Compile SCSS/JS assets locally
  • Sync all changes (source files + compiled assets) to remote server via SSH
  • No need for FTP/SFTP - works with SSH-only access
  • Perfect for staging/live servers where you can't install Node.js

Features:

  • File watcher that syncs changes in real-time
  • Excludes source files and node_modules from sync
  • Easy setup with npm scripts
  • Works with any remote server accessible via SSH

Prerequisites: Node.js locally, SSH access to remote server

Usage:

Download source

rsync -avz username@server:/var/www/html/ ./

Updated package.json

{
  "scripts": {
    "sync": "node sync-watcher.js",
    "dev": "concurrently \"npm run watch\" \"npm run sync\"",
    "download": "./download.sh",
    "upload-all": "rsync -avz --progress --exclude='node_modules' --exclude='src' --exclude='.git' ./ username@server:/var/www/html/"
  }
}
#!/bin/bash
REMOTE_HOST="username@server"
REMOTE_PATH="/var/www/html/"
LOCAL_PATH="./"
if [ -z "$1" ]; then
# Download all files with exclusions
rsync -avz \
--exclude="node_modules" \
--exclude=".git" \
--exclude="package.json" \
--exclude="package-lock.json" \
--exclude=".gitignore" \
"$REMOTE_HOST:$REMOTE_PATH" "$LOCAL_PATH"
else
# Download specific file
rsync -avz "$REMOTE_HOST:$REMOTE_PATH$1" "$LOCAL_PATH$1"
fi
const chokidar = require('chokidar');
const { exec } = require('child_process');
const path = require('path');
const config = {
remote: {
user: 'your-username',
host: 'your-server.com',
path: '/var/www/html/'
}
};
const remotePath = `${config.remote.user}@${config.remote.host}:${config.remote.path}`;
function syncFile(filePath) {
// Skip source files and node_modules
if (filePath.includes('src/') || filePath.includes('node_modules/')) {
return;
}
const relativePath = path.relative(process.cwd(), filePath);
const remoteFilePath = `${remotePath}${relativePath}`;
console.log(`πŸ“ Syncing: ${relativePath}`);
exec(`scp "${filePath}" "${remoteFilePath}"`, (error) => {
if (error) {
console.error(`❌ Error: ${error.message}`);
return;
}
console.log(`βœ… Synced: ${relativePath}`);
});
}
// Watch for changes
const watcher = chokidar.watch('.', {
ignored: [
'node_modules/**',
'src/**',
'.git/**',
'**/.DS_Store',
'package*.json',
'webpack.config.js',
'sync-watcher.js'
],
persistent: true,
ignoreInitial: true
});
watcher
.on('change', syncFile)
.on('add', syncFile);
console.log('πŸ‘€ Watching for file changes...');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment