آموزش سرور

بکاپ خودکار سرور با rsync و cron؛ ارسال روزانهٔ فایل‌ها و دیتابیس به سرور دوم

تهیه: کلودیفای (نگارش با کمک هوش مصنوعی) · انتشار: · زمان مطالعه: ۷ دقیقه

root@server: ~$ /usr/local/bin/pull-backup.shreceiving incremental file list...backup ok ...$ ls /srv/backups/main2026-10-29 2026-10-30 2026-10-31 latersynccronآموزش سروربکاپ خودکار سرور با rsync وcron؛ ارسال روزانهٔ فایل‌ها ودیتابیس به سرور دوممجلهٔ کلودیفایclodify.net/blog
پاسخ کوتاه

بکاپی که روی همان سرور بماند، در صورت خرابی دیسک، هک یا حذف سرور از بین می‌رود. یک سرور دوم در لوکیشن دیگر بگیرید، یک کلید SSH اختصاصی برای بکاپ بسازید، دیتابیس را با mysqldump یا pg_dump خروجی بگیرید و فایل‌ها را با rsync روی SSH منتقل کنید. با گزینهٔ link-dest نسخه‌های روزانه بدون اشغال فضای تکراری نگه دارید، اسکریپت را در cron زمان‌بندی کنید و هر چند وقت یک‌بار بازیابی را واقعاً تست کنید.

قاعدهٔ اول بکاپ: روی همان سرور نماند

بسیاری از مدیران سرور «بکاپ» دارند، اما فایل بکاپ در پوشه‌ای روی همان سرور است. چنین بکاپی در برابر حذف تصادفی یک فایل مفید است، اما در برابر سناریوهای واقعی فاجعه، یعنی خرابی دیسک، نفوذ و رمزگذاری داده‌ها توسط باج‌افزار، حذف سرور به‌دلیل تمام شدن اعتبار یا اشتباه در یک دستور مخرب، هیچ کمکی نمی‌کند.

قاعدهٔ شناخته‌شدهٔ «۳-۲-۱» می‌گوید: سه نسخه از داده، روی دو نوع رسانهٔ متفاوت، که یکی از آن‌ها در مکان دیگری باشد. برای یک سرور مجازی، ساده‌ترین پیاده‌سازی عملی این است که هر شب از داده‌ها بکاپ بگیرید و آن را به یک سرور دوم در دیتاسنتر یا حتی کشور دیگری بفرستید. ابزار استاندارد این کار rsync روی SSH است: رایگان، روی همهٔ توزیع‌ها موجود، رمزنگاری‌شده و هوشمند در ارسال فقط تغییرات.

بکاپ Pull از سرور اصلی
dumpکشیدن دادهذخیرهسرور اصلیسایت، دیتابیس، /etcخروجی دیتابیسmysqldump ساعت ۲:۳۰rsync روی SSHفقط تغییراتسرور بکاپنسخه‌های روزانهdumpکشیدن دادهذخیرهسرور اصلیسایت، دیتابیس، /etcخروجی دیتابیسmysqldump ساعت ۲:۳۰rsync روی SSHفقط تغییراتسرور بکاپنسخه‌های روزانه
شکل ۱ سرور بکاپ هر شب داده‌ها را می‌کشد؛ سرور اصلی هیچ دسترسی‌ای به بکاپ‌ها ندارد.

معماری پیشنهادی: Pull به‌جای Push

دو روش برای انتقال وجود دارد:

  • Push: سرور اصلی بکاپ را به سرور بکاپ می‌فرستد. ساده است، اما سرور اصلی باید دسترسی نوشتن روی سرور بکاپ داشته باشد؛ اگر سرور اصلی هک شود، مهاجم می‌تواند بکاپ‌ها را هم پاک کند.
  • Pull: سرور بکاپ به سرور اصلی وصل می‌شود و داده‌ها را می‌کشد. سرور اصلی هیچ دسترسی‌ای به سرور بکاپ ندارد و نفوذ به آن، بکاپ‌ها را در خطر قرار نمی‌دهد.

روش Pull امن‌تر است و در این آموزش از آن استفاده می‌کنیم. در ادامه، «سرور اصلی» سروری است که سایت یا برنامه روی آن اجرا می‌شود و «سرور بکاپ» سرور دوم است.

از چه چیزهایی بکاپ بگیریم و از چه چیزهایی نه؟

پیش از نوشتن اسکریپت، فهرست کنید بازسازی کدام داده‌ها بدون بکاپ ممکن نیست. این‌ها اولویت اول‌اند:

  • دیتابیس‌ها: سفارش‌ها، کاربران، محتوای سایت؛ ارزشمندترین و غیرقابل‌جایگزین‌ترین بخش.
  • فایل‌های آپلودشده: تصاویر محصولات، فایل‌های کاربران و هر چیزی که در پوشهٔ uploads جمع می‌شود.
  • فایل‌های پیکربندی: پوشهٔ /etc (به‌خصوص پیکربندی Nginx، PHP، cron و systemd)، فایل‌های .env برنامه‌ها و فایل‌های Compose. بازنویسی این‌ها از حافظه ساعت‌ها وقت می‌گیرد.
  • گواهی‌ها و کلیدها: پوشهٔ /etc/letsencrypt و کلیدهای مهم؛ هرچند گواهی‌ها دوباره قابل صدورند.

در مقابل، این‌ها معمولاً نیازی به بکاپ ندارند و فقط حجم و زمان بکاپ را بالا می‌برند: پوشه‌های کش، فایل‌های موقت، node_modules و محیط‌های مجازی پایتون (از روی فایل وابستگی‌ها دوباره ساخته می‌شوند)، ایمیج‌های داکر (از رجیستری دوباره دانلود می‌شوند) و خود سیستم‌عامل. کد برنامه هم اگر در گیت نگهداری می‌شود، از آنجا قابل بازیابی است. با گزینهٔ --exclude در rsync این مسیرها را کنار بگذارید.

گام ۱: آماده‌سازی خروجی دیتابیس روی سرور اصلی

کپی کردن مستقیم فایل‌های دیتابیس در حال اجرا ممکن است بکاپ ناسالم بسازد. بهتر است روی سرور اصلی، هر شب پیش از زمان بکاپ، خروجی منطقی دیتابیس گرفته شود. یک اسکریپت بسازید:

sudo mkdir -p /var/backups/db
sudo nano /usr/local/bin/db-dump.sh
#!/bin/bash
set -euo pipefail
D=/var/backups/db
# MySQL / MariaDB (اطلاعات ورود در /root/.my.cnf)
mysqldump --single-transaction --routines --all-databases | gzip > $D/mysql-$(date +%F).sql.gz
# PostgreSQL
# sudo -u postgres pg_dumpall | gzip > $D/pg-$(date +%F).sql.gz
# فقط هفت روز آخر روی سرور اصلی بماند
find $D -name "*.sql.gz" -mtime +7 -delete
sudo chmod 700 /usr/local/bin/db-dump.sh
sudo /usr/local/bin/db-dump.sh && ls -lh /var/backups/db

گزینهٔ --single-transaction برای جداول InnoDB بکاپ سازگار می‌گیرد بدون اینکه جداول را قفل کند. رمز دیتابیس را در فایل /root/.my.cnf با مجوز ۶۰۰ نگه دارید، نه داخل اسکریپت.

گام ۲: کلید SSH اختصاصی و محدود روی سرور بکاپ

روی سرور بکاپ یک کلید بدون عبارت عبور فقط برای این کار بسازید:

ssh-keygen -t ed25519 -f ~/.ssh/backup_key -N "" -C "backup-pull"
cat ~/.ssh/backup_key.pub

کلید عمومی را در authorized_keys کاربر root (یا کاربری با دسترسی خواندن داده‌ها) روی سرور اصلی قرار دهید. برای امنیت بیشتر، می‌توانید با پیشوند from="آی‌پی سرور بکاپ" در ابتدای همان خط، استفاده از این کلید را فقط به آی‌پی سرور بکاپ محدود کنید. اگر با کلیدهای SSH آشنا نیستید، آموزش کلید SSH را ببینید.

اتصال را تست کنید:

ssh -i ~/.ssh/backup_key root@203.0.113.10 "hostname"
root@backup: ~
$ /usr/local/bin/pull-backup.shreceiving incremental file list...backup ok ...$ ls /srv/backups/main2026-10-29  2026-10-30  2026-10-31  latest$ du -sh --apparent-size /srv/backups/main/2026-10-31...   /srv/backups/main/2026-10-31$ 
شکل ۲ هر پوشهٔ روزانه یک نسخهٔ کامل است، اما فایل‌های تغییرنکرده با hard link فضای اضافه نمی‌گیرند.

گام ۳: اسکریپت بکاپ روی سرور بکاپ با نسخه‌های روزانه

اگر هر شب فقط یک پوشه را همگام کنید، فایلی که امروز اشتباهی حذف یا خراب شده، امشب در بکاپ هم حذف یا خراب می‌شود. به نسخه‌های تاریخ‌دار نیاز دارید. ترفند rsync برای این کار گزینهٔ --link-dest است: فایل‌هایی که نسبت به نسخهٔ دیروز تغییر نکرده‌اند به‌صورت hard link ساخته می‌شوند و فضای اضافه نمی‌گیرند؛ فقط فایل‌های تغییرکرده واقعاً کپی می‌شوند. هر پوشهٔ روزانه یک نسخهٔ کامل به نظر می‌رسد.

sudo nano /usr/local/bin/pull-backup.sh
#!/bin/bash
set -euo pipefail
SRC=root@203.0.113.10
KEY=/root/.ssh/backup_key
DEST=/srv/backups/main
TODAY=$DEST/$(date +%F)
LAST=$DEST/latest
mkdir -p $DEST
rsync -aHAX --delete --numeric-ids \
  -e "ssh -i $KEY" \
  --exclude='/var/www/*/cache/' \
  --link-dest=$LAST \
  $SRC:/var/www $SRC:/etc $SRC:/var/backups/db $SRC:/root \
  $TODAY/
ln -sfn $TODAY $LAST
# حذف نسخه‌های قدیمی‌تر از ۳۰ روز
find $DEST -maxdepth 1 -type d -name "20*" -mtime +30 -exec rm -rf {} +
echo "backup ok $(date)"
sudo chmod 700 /usr/local/bin/pull-backup.sh
sudo /usr/local/bin/pull-backup.sh

بار اول کل داده‌ها منتقل می‌شود و ممکن است طول بکشد؛ اجراهای بعدی فقط تغییرات را می‌فرستند. فهرست مسیرها را با ساختار سرور خودتان تنظیم کنید: پوشهٔ سایت‌ها، فایل‌های پیکربندی در /etc، خروجی دیتابیس و هر پوشهٔ دیگری که دادهٔ مهم دارد. اگر از داکر استفاده می‌کنید، پوشه‌های Volume یا پوشهٔ پروژه‌های Compose را هم اضافه کنید.

گام ۴: زمان‌بندی با cron

روی سرور اصلی، خروجی دیتابیس را مثلاً ساعت ۲:۳۰ و روی سرور بکاپ، دریافت را ساعت ۳:۰۰ زمان‌بندی کنید:

# روی سرور اصلی: sudo crontab -e
30 2 * * * /usr/local/bin/db-dump.sh >> /var/log/db-dump.log 2>&1

# روی سرور بکاپ: sudo crontab -e
0 3 * * * flock -n /tmp/pull-backup.lock /usr/local/bin/pull-backup.sh >> /var/log/pull-backup.log 2>&1

flock جلوی اجرای هم‌زمان دو بکاپ را می‌گیرد، مثلاً اگر یک بکاپ بزرگ بیش از یک روز طول بکشد. نکته‌های بیشتر دربارهٔ محیط cron و منطقهٔ زمانی را در آموزش Cron در لینوکس بخوانید.

گام ۵: نظارت و هشدار

بکاپی که بی‌صدا شکست بخورد، بدتر از نداشتن بکاپ است، چون حس امنیت کاذب می‌دهد. حداقل کارها:

  • هر چند روز یک‌بار لاگ را بخوانید و تاریخ آخرین پوشهٔ بکاپ را بررسی کنید.
  • در انتهای اسکریپت، در صورت خطا برای خودتان پیام بفرستید؛ مثلاً با یک ربات تلگرام از طریق curl به API آن.
  • فضای دیسک سرور بکاپ را زیر نظر داشته باشید؛ پر شدنش یعنی شکست بکاپ‌های بعدی.
چرخهٔ کامل بکاپ
  1. خروجی دیتابیس

    mysqldump یا pg_dump روی سرور اصلی، هر شب.

  2. کشیدن با rsync

    سرور بکاپ با کلید محدود، فایل‌ها و dumpها را می‌کشد.

  3. نسخه‌بندی

    link-dest پوشه‌های روزانه می‌سازد؛ نسخه‌های قدیمی حذف می‌شوند.

  4. هشدار

    در صورت شکست، پیام بفرستید و لاگ را بررسی کنید.

  5. تست بازیابی

    ماهانه روی یک سرور موقت بازیابی را امتحان کنید.

شکل ۳ بکاپ بدون تست بازیابی فقط یک فرض است.

گام ۶: بازیابی را واقعاً تست کنید

بکاپ تا وقتی بازیابی‌اش را امتحان نکرده‌اید، فقط یک فرض است. هر ماه یک بار:

  1. یک سرور موقت بسازید (سرور ساعتی برای این کار ایده‌آل است).
  2. فایل‌ها را با rsync از سرور بکاپ به آن منتقل کنید.
  3. دیتابیس را از فایل خروجی بازگردانید: gunzip < mysql-DATE.sql.gz | mysql.
  4. بررسی کنید سایت یا برنامه با داده‌های بکاپ بالا می‌آید.
  5. سرور موقت را حذف کنید.

با سرورهای ساعتی کلودیفای این تمرین فقط هزینهٔ چند ساعت استفاده دارد. برای سرور بکاپ هم انتخاب لوکیشن متفاوت از سرور اصلی منطقی است؛ مثلاً سرور اصلی در ایران و سرور بکاپ در دیتاسنتر دیگر یا خارج از کشور. اگر ترافیک دانلود سرور ایران محاسبه می‌شود، در نظر داشته باشید که در روش Pull داده از سرور اصلی خارج می‌شود؛ جزئیات در صورتحساب ترافیک سرور ایران آمده است.

سؤالات متداول

rsync بهتر است یا اسنپ‌شات ارائه‌دهنده؟

هر دو مفیدند و جایگزین هم نیستند. اسنپ‌شات کل دیسک را سریع ذخیره می‌کند اما معمولاً نزد همان ارائه‌دهنده می‌ماند. بکاپ با rsync به سرور دیگر، داده‌ها را از ارائه‌دهنده و دیتاسنتر اصلی مستقل می‌کند. بهترین حالت داشتن هر دوست.

چرا روش Pull امن‌تر از Push است؟

در Pull سرور اصلی هیچ دسترسی‌ای به سرور بکاپ ندارد. اگر مهاجم به سرور اصلی نفوذ کند، نمی‌تواند بکاپ‌ها را حذف یا رمزگذاری کند؛ در حالی که در Push کلید دسترسی به سرور بکاپ روی سرور اصلی است.

فایل‌هایی که نسبت به بکاپ قبلی تغییر نکرده‌اند، به‌جای کپی دوباره به‌صورت hard link به همان فایل قبلی ساخته می‌شوند. هر پوشهٔ روزانه کامل به نظر می‌رسد، اما فقط فایل‌های تغییرکرده فضای جدید می‌گیرند.

آیا بکاپ باید رمزنگاری شود؟

انتقال با SSH رمزنگاری‌شده است. اگر سرور بکاپ نزد ارائه‌دهندهٔ دیگری است یا داده‌های حساس دارید، رمزنگاری بکاپ در حالت ذخیره هم توصیه می‌شود؛ ابزارهایی مثل restic و borg این کار را به‌صورت داخلی انجام می‌دهند.

آماده‌اید؟ سرورتان را بسازید.

از ۱٬۲۰۰ تومان در ساعت · پرداخت ریالی

سرورتان را همین حالا بسازید.

ساعتی بپردازید. هر وقت خواستید حذف کنید.