بکاپ و امنیت

آموزش بکاپ‌گیری از سرور لینوکس — اسکریپت، زمان‌بندی و ریستور

بکاپ‌گیری از سرور لینوکس: کارت ترمینالی که مسیر یک نسخه‌ی پشتیبان را از آرشیو شبانه‌ی tar و دامپ دیتابیس تا انتقال با rsync به سرور دوم و اسنپ‌شات رمزشده‌ی restic نشان می‌دهد و در انتها با تست ریستور تأیید می‌کند

بکاپ‌گیری از سرور لینوکس تنها چیزی است که بین شما و یک روز واقعاً بد می‌ایستد: هارددیسک‌ها بدون اطلاع قبلی می‌میرند، یک rm اشتباه در سه ثانیه حاصل سه ماه کار را پاک می‌کند و باج‌افزارها همیشه نیمه‌شب می‌رسند. اما بکاپی که هرگز ریستور نشده، فقط یک فایل است؛ نه یک تضمین. در این راهنما مسیر را قدم‌به‌قدم جلو می‌بریم: قانون ۳-۲-۱، فهرست‌کردن دارایی‌های سرور، اسکریپت شبانه با tar و cron، دامپ MySQL و MariaDB، انتقال با rsync به سرور دوم، اسنپ‌شات‌های رمزنگاری‌شده‌ی restic و مهم‌ترین قدمی که بیشتر مدیرها فراموشش می‌کنند: تست ریستور.

قانون ۳-۲-۱ به زبان آدمیزاد

هر استراتژی بکاپ جدی روی یک قانون ساده سوار است:

  • ۳ نسخه از هر داده‌ی مهم داشته باشید (نسخه‌ی اصلی + دو کپی).
  • کپی‌ها روی ۲ سیستم متفاوت باشند — نه دو پوشه روی همان دیسک.
  • ۱ نسخه کاملاً بیرون از سرور اصلی نگه‌داری شود.

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

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

💡 نکته: لازم نیست از کل سیستم‌عامل بکاپ بگیرید. سیستم‌عامل قابل بازسازی است؛ چیزی که قابل بازسازی نیست، داده‌ی شماست: کانفیگ‌ها، فایل‌های سایت و دیتابیس.

دقیقاً از چه چیزی بکاپ بگیریم؟

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

  • /etc — همه‌ی کانفیگ‌ها: وب‌سرور، PHP، فایروال، یونیت‌های systemd. حجمش ناچیز و ارزشش بیشترین است.
  • /var/www یا /home/*/public_html — فایل‌های سایت، آپلودها و فایل‌های .env.
  • دامپ دیتابیس — نه پوشه‌ی خام آن؛ در بخش بعد دلیلش را می‌بینید.
  • کرانتب کاربران، گواهی‌های TLS (/etc/letsencrypt) و ~/.ssh/authorized_keys.

و به همان اندازه مهم است بدانید چه چیزی نباید داخل آرشیو برود: کش، فایل‌های موقت، لاگ‌های حجیم و node_modules — این‌ها فضا و زمان می‌خورند بی‌آنکه «داده» باشند. GNU tar برای همین --exclude=PATTERN را دارد که فایل‌های منطبق بر یک الگوی glob را کنار می‌گذارد، و --one-file-system که «هنگام ساخت آرشیو در همان فایل‌سیستم می‌ماند» — یعنی اگر جایی زیر این مسیرها پارتیشن دیگری mount شده باشد، ناخواسته بلعیده نمی‌شود. حالا پیش از هر تصمیمی، اندازه‌ها را ببینید:

du -sh /etc /var/www /home /var/lib/mysql
12M     /etc
3.4G    /var/www
860M    /home
2.1G    /var/lib/mysql

df -h /var/backups
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        79G   21G   55G  28% /

حالا عدد دارید: با فشرده‌سازی هر آرشیو شبانه حدود ۱.۵ تا ۲ گیگابایت می‌شود و نگه‌داشتن ۱۴ نسخه یعنی نزدیک ۲۸ گیگابایت. همین محاسبه جلوی رایج‌ترین حادثه‌ی بکاپ را می‌گیرد: پرشدن دیسک توسط خودِ بکاپ.

اسکریپت بکاپ‌گیری از سرور لینوکس با tar و cron

ساده‌ترین شکل قابل‌اتکای بکاپ، یک آرشیو فشرده‌ی شبانه از مسیرهای مهم است. با فهرستی که ساختید، /root/backup.sh را بنویسید:

#!/bin/bash
set -euo pipefail

DATE=$(date +%F)
DEST=/var/backups/files
mkdir -p "$DEST"

# a rebuild shortcut (Debian/Ubuntu): what was installed here
dpkg --get-selections > /root/packages.list

tar -czf "$DEST/backup-$DATE.tar.gz" \
    --one-file-system \
    --exclude='*/cache/*' --exclude='*/node_modules/*' \
    /etc /var/www /home /root/packages.list

# retention: delete archives older than 14 days
find "$DEST" -name "backup-*.tar.gz" -mtime +14 -delete

سوییچ‌ها: -c ساخت آرشیو، -z فشرده‌سازی gzip و -f نام فایل خروجی. خط set -euo pipefail باعث می‌شود اسکریپت با اولین خطا متوقف شود، نه این‌که بی‌سروصدا یک آرشیو ناقص بسازد. برای داده‌ی بزرگ هم به‌جای -z سراغ --zstd بروید.

یک نکته که خیلی‌ها اشتباه می‌گیرند: -p را لازم نیست موقع ساخت آرشیو بنویسید. tar سطح دسترسی و مالکیت را همیشه ثبت می‌کند؛ -p یک گزینه‌ی استخراج است که طبق راهنمای رسمی «سطح دسترسی فایل‌های استخراج‌شده را به همان چیزی که در آرشیو ثبت شده تنظیم می‌کند (پیش‌فرض برای کاربر ریشه)».

زمان‌بندی: بکاپ خودکار سرور با cron

بکاپی که به حافظه‌ی انسان وابسته باشد، دیر یا زود فراموش می‌شود. با crontab -e این دو خط را اضافه کنید:

MAILTO=admin@example.com
30 3 * * * /usr/bin/flock -n /var/lock/backup.lock /root/backup.sh >> /var/log/backup.log 2>&1

سه چیز اینجا عمدی است. MAILTO: طبق راهنمای crontab اگر تعریف و ناتهی باشد، خروجی هر اجرا به همان نشانی ایمیل می‌شود — پس شبی که اسکریپت خطا بدهد خبردار می‌شوید. flock -n: «اگر قفل بلافاصله به‌دست نیامد، به‌جای انتظار شکست می‌خورد»، یعنی دو tar هم‌زمان روی یک فایل نمی‌نویسند. و مسیر کامل باینری‌ها: کرون SHELL را روی /bin/sh می‌گذارد و مسیر جست‌وجوی برنامه‌ها بسیار کوتاه‌تر از ترمینال است؛ اسکریپتی که دستی جواب می‌دهد و در کرون «command not found» می‌گیرد، قربانی همین است. جزئیات در راهنمای کرون‌جاب لینوکس.

سیاست نگهداری (Retention)

خط find آرشیوهای قدیمی را پاک می‌کند تا دیسک پر نشود. یک ریزه‌کاری: find هنگام محاسبه‌ی «چند دوره‌ی ۲۴ساعته گذشته» بخش کسری را نادیده می‌گیرد، پس -mtime +14 در عمل یعنی فایل‌های دست‌کم ۱۵روزه. الگوی رایج: ۷ نسخه‌ی روزانه + ۴ هفتگی + ۳ ماهانه. نگه‌داشتن فقط «آخرین بکاپ» خطرناک است؛ اگر خرابی داده چند روز دیرتر کشف شود، آخرین بکاپ هم خراب است.

⚠️ ترتیب دستورها را عوض نکنید: اول بکاپ جدید را بسازید، بعد قدیمی‌ها را پاک کنید. اسکریپتی که اول پاک‌سازی می‌کند و بعد در ساخت آرشیو خطا می‌دهد، شما را بدون هیچ نسخه‌ای تنها می‌گذارد.

بکاپ دیتابیس MySQL و MariaDB با mysqldump

کپی مستقیم پوشه‌ی /var/lib/mysql در حالی که سرویس کار می‌کند، تقریباً همیشه یک بکاپ ناسازگار و غیرقابل‌ریستور تحویل می‌دهد. راه درست، دامپ منطقی است. اول اطلاعات ورود را جایی امن بگذارید تا رمز در تاریخچه‌ی شل و خروجی ps دیده نشود: روش کلاسیک فایل /root/.my.cnf با chmod 600 است و روش تمیزتر، ابزار mysql_config_editor که همان اطلاعات را در .mylogin.cnf ذخیره می‌کند — با این هشدار که خود مستندات MySQL می‌دهد: این «مبهم‌سازی» است نه رمزنگاری واقعی و مهاجمی را که به سرور دسترسی دارد متوقف نمی‌کند.

mysql_config_editor set --login-path=backup --host=localhost --user=root --password

mkdir -p /var/backups/db
mysqldump --login-path=backup --all-databases --single-transaction \
    --quick --routines --events \
    | gzip > /var/backups/db/all-db-$(date +%F).sql.gz

ls -lh /var/backups/db/
-rw-r--r-- 1 root root 214M Sep  8 03:31 all-db-2026-09-08.sql.gz

سوییچ --single-transaction پیش از شروع دامپ یک BEGIN صادر می‌کند و نمای سازگاری می‌گیرد — اما فقط برای جدول‌های InnoDB؛ اگر هنوز جدول MyISAM دارید، هیچ تضمینی برایشان نیست. --quick ردیف‌ها را یکی‌یکی می‌گیرد تا جدول بزرگ کل حافظه را نبلعد. و دو سوییچ آخر لازم‌اند چون پیش‌فرض نیستند: --routines رویه‌ها و توابع ذخیره‌شده را می‌آورد و --events رویدادهای زمان‌بندی‌شده را؛ بدون این‌ها دامپ ظاهراً کامل است ولی منطق سمت دیتابیس را ندارد.

اگر روی MariaDB هستید نام ابزار عوض شده: از نسخه‌ی ۱۰.۵ نام رسمی mariadb-dump است و mysqldump فقط یک لینک نمادین؛ از نسخه‌ی ۱۱.۰ این لینک منسوخ اعلام شده و از ایمیج رسمی داکر حذف شده است — اسکریپت‌های قدیمی را به‌روز کنید تا یک ارتقای معمولی بکاپ شبانه‌تان را از کار نیندازد. و اگر چند دیتابیس دارید برای هرکدام فایل جداگانه بگیرید: برگرداندن دیتابیس یک سایت خراب نباید مستلزم دست‌کاری دیتابیس نُه سایت سالم باشد.

اگر دیتابیس‌تان PostgreSQL است

pg_dump طبق مستندات رسمی حتی وقتی دیتابیس در حال استفاده است خروجی سازگار می‌سازد و جلوی خواندن و نوشتن بقیه را نمی‌گیرد — اما فقط یک دیتابیس را دامپ می‌کند؛ برای اشیای سراسری مثل نقش‌ها و tablespaceها به pg_dumpall نیاز دارید:

sudo -u postgres pg_dump -Fc myapp > /var/backups/db/myapp-$(date +%F).dump
sudo -u postgres pg_dumpall --globals-only > /var/backups/db/globals-$(date +%F).sql

قالب -Fc پیش‌فرض فشرده است و اجازه می‌دهد موقع بازیابی با pg_restore فقط بخشی از اشیا را انتخاب و مرتب کنید.

نسخه‌ی دوم: rsync بکاپ‌ها به سرور دیگر

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

rsync -a --stats /var/backups/ backup@203.0.113.50:/srv/backup/web1/

Number of files: 17 (reg: 16, dir: 1)
Number of regular files transferred: 2
Total file size: 12,930,469,888 bytes
Total transferred file size: 1,847,209,984 bytes

sent 1,847,432,118 bytes  received 4,210 bytes  9,213,163.43 bytes/sec
total size is 12,930,469,888  speedup is 7.00

زیبایی rsync در افزایشی‌بودن آن است: فقط فایل‌های جدید یا تغییرکرده منتقل می‌شوند. سوییچ -a طبق راهنمای رسمی معادل -rlptgoD است — بازگشتی، با حفظ لینک نمادین، سطح دسترسی، زمان، مالک و گروه — ولی ACL و ویژگی‌های توسعه‌یافته (xattr) را شامل نمی‌شود؛ اگر لازم‌اند، -A و -X را اضافه کنید.

یک ارتقای کم‌هزینه و پرارزش، اسنپ‌شات‌های نسخه‌دار با --link-dest است: فایل‌های تغییرنکرده به‌جای کپی دوباره به نسخه‌ی قبلی hardlink می‌شوند، پس هر شب یک پوشه‌ی کامل دارید ولی فضای مصرفی فقط به اندازه‌ی تغییرات است:

TODAY=$(date +%F); YEST=$(date -d yesterday +%F)
rsync -a --link-dest=/srv/backup/web1/$YEST \
      /var/backups/ backup@203.0.113.50:/srv/backup/web1/$TODAY/

انتقال شبانه‌ی چند گیگابایت روی سقف ترافیک سرور بی‌اثر نیست؛ پیش از زمان‌بندی نگاهی به راهنمای مصرف پهنای باند سرور بیندازید. و هفته‌ای یک بار روی مقصد ls -lh بزنید: بکاپی که سه هفته پیش از کار افتاده، از نداشتن بکاپ هم خطرناک‌تر است — چون احساس امنیت دروغین می‌دهد.

باج‌افزار: چرا سرور نباید اجازه‌ی حذف روی مقصد داشته باشد

اینجا مهم‌ترین تفاوت «کپی گرفتن» و «بکاپ داشتن» است: اگر مهاجم روی سرور اصلی دسترسی ریشه بگیرد، همان کلید SSH و همان دستور rsync در اختیار اوست — و اولین کار باج‌افزارهای امروزی، پاک‌کردن یا رمزکردن بکاپ‌هاست.

⚠️ سوییچ --delete را برای مقصد بکاپ به‌کار نبرید: فایل‌های اضافی مقصد را حذف می‌کند تا آینه‌ی مبدأ شود. اما نیاوردنش در خط cron هیچ محافظتی نمی‌سازد؛ کسی که سرور را گرفته خودش می‌تواند دستور را با --delete اجرا کند.

محافظت واقعی باید سمت مقصد باشد و سه شکل عملی دارد. اول، کلید SSH سرور مبدأ را روی سرور بکاپ به یک دستور اجباری ببندید: در authorized_keys مقصد، پیشوند restrict,command="…" کاری می‌کند که آن کلید اصلاً شل نگیرد. دوم، مدل را برعکس کنید: به‌جای این‌که سرور وب بکاپ را هل بدهد، سرور بکاپ آن را بکشد؛ در این حالت سرور وب هیچ کلیدی به مقصد ندارد. سوم، روی مقصد نسخه‌های تاریخ‌دار نگه دارید تا بازنویسی امروز، نسخه‌های دیروز را از بین نبرد. بقیه‌ی لایه‌های سخت‌سازی در راهنمای امنیت سرور لینوکس جمع شده است.

restic؛ بکاپ رمزنگاری‌شده و افزایشی

روش tar یک ضعف آشکار دارد: هر شب یک آرشیو کاملِ جدید می‌سازد، حتی اگر دو فایل عوض شده باشد. restic سه چیز را با هم می‌آورد: رمزنگاری سمت مبدأ (مقصد فقط داده‌ی رمزشده می‌بیند)، حذف داده‌ی تکراری، و اسنپ‌شات‌های افزایشی که هرکدام مثل یک بکاپ کامل و مستقل قابل ریستورند.

export RESTIC_REPOSITORY=sftp:backup@203.0.113.50:/srv/restic
export RESTIC_PASSWORD_FILE=/root/.restic-pass
restic init
restic backup --exclude-file=/root/backup-excludes.txt /etc /var/www
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic snapshots

ID        Time                 Host  Tags  Paths
-----------------------------------------------------
a1b9c73f  2026-09-08 03:31:02  web1        /etc
                                           /var/www
7d2e4406  2026-09-07 03:31:04  web1        /etc
                                           /var/www
-----------------------------------------------------
2 snapshots

init مخزن را یک بار می‌سازد و backup هر بار فقط تغییرات را می‌فرستد. forget --prune همان سیاست نگهداری است اما داخل خود ابزار: طبق مستندات، --keep-daily 7 یعنی «از هفت روز اخیر که دست‌کم یک اسنپ‌شات دارند، فقط تازه‌ترین اسنپ‌شات هر روز نگه داشته شود» و --prune داده‌ی بی‌ارجاع را از مخزن پاک می‌کند. RESTIC_PASSWORD_FILE هم رمز را از فایل می‌خواند تا اجرا در cron ممکن شود.

دو هشدار جدی. اول، رمز مخزن: مستندات restic صریح است که گم‌کردن رمز یعنی داده‌ی شما به‌طور برگشت‌ناپذیر از دست رفته است — آن رمز را جایی خارج از سرور نگه دارید. دوم، نسخه‌ی بسته‌ی توزیع معمولاً عقب است: اوبونتو ۲۴.۰۴ نسخه‌ی ۰.۱۶.۴ را دارد در حالی که نسخه‌ی پایدار فعلی ۰.۱۹.۱ است، و خود مستندات می‌گوید در این حالت می‌توانید باینری رسمی پروژه را مستقیم دانلود و اجرا کنید. یک عادت هم که کم به آن اشاره می‌شود: restic check ساختار مخزن را می‌سنجد ولی پیش‌فرض محتوای پک‌فایل‌ها را نمی‌خواند؛ با restic check --read-data-subset=5% هر بار بخشی تصادفی از خودِ داده خوانده و تأیید می‌شود.

tar یا restic یا اسنپ‌شات ارائه‌دهنده؟

هیچ‌کدام جایگزین کامل دیگری نیست؛ هر کدام یک سناریوی خرابی متفاوت را پوشش می‌دهد:

روشچه چیزی ذخیره می‌شودبازیابی یک فایلرمزنگاری در مقصدتله‌ی اصلی
tar + cronآرشیو کامل در هر اجراساده، با tar -xندارد، مگر خودتان اضافه کنیدرشد خطی فضا
rsync سادهآینه‌ی وضعیت فعلیسریع‌ترین حالتفقط حین انتقال با SSHبدون نسخه‌بندی؛ خرابی هم آینه می‌شود
rsync با --link-destاسنپ‌شات روزانه با hardlinkهر روز یک پوشه‌ی کاملفقط حین انتقالوابسته به پشتیبانی مقصد از hardlink
resticاسنپ‌شات افزایشی و بدون تکراربا restore --includeبله، سمت مبدأگم‌شدن رمز مخزن یعنی پایان کار
افزودنی ارائه‌دهندهکل دیسک ماشیننه؛ کل دیسک بازنویسی می‌شودسمت ارائه‌دهندهداخل همان زیرساخت

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

چقدر داده و چقدر زمان حاضرید از دست بدهید؟

پیش از انتخاب ابزار دو عدد را مشخص کنید. RPO یعنی حداکثر داده‌ای که از دست‌رفتنش را می‌پذیرید و مستقیماً از فاصله‌ی بین دو بکاپ می‌آید: بکاپ شبانه یعنی در بدترین حالت کار یک روز رفته است. RTO یعنی حداکثر زمانی که تا برگشتن سرویس تحمل می‌کنید.

برای یک وبلاگ RPO یک‌روزه منطقی است؛ برای فروشگاهی با چند صد سفارش در روز فاجعه است و باید فاصله‌ی بکاپ دیتابیس را به چند ساعت برسانید، در حالی که فایل‌های سایت می‌توانند شبانه بمانند. سمت RTO هم بپرسید: سرور جایگزین را از کجا می‌آورید و DNS با چه TTLای به مقصد جدید اشاره می‌کند؟

تست ریستور: بکاپی که هرگز ریستور نشده، امید است نه بکاپ

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

# 1. is the archive itself intact?
gzip -t /var/backups/files/backup-2026-09-07.tar.gz && echo "archive OK"
archive OK

# 2. list the contents
tar -tzf /var/backups/files/backup-2026-09-07.tar.gz | head -3
etc/
etc/nginx/nginx.conf
etc/nginx/sites-available/default

# 3. extract into a test dir, never into /
mkdir -p /tmp/restore-test
tar -xzpf /var/backups/files/backup-2026-09-07.tar.gz -C /tmp/restore-test

# 4. the DB dump: verify it, then restore ONE database into a scratch DB
gunzip -t /var/backups/db/all-db-2026-09-07.sql.gz && echo "dump OK"
dump OK

mysqldump --login-path=backup myshop_db | gzip > /tmp/one-db.sql.gz
mysql -e "CREATE DATABASE restore_test"
gunzip -c /tmp/one-db.sql.gz | mysql restore_test

قدم اول را دست‌کم نگیرید: gzip -t چند ثانیه طول می‌کشد و همان‌جا می‌گوید آرشیو نصفه‌کاره است یا نه. -p هم در خط استخراج آمده — جای درستش. و در قدم چهارم دقت کنید: دامپ --all-databases داخل خودش دستور USE دارد، پس ریختنش در یک دیتابیس آزمایشی کار نمی‌کند و در عمل دیتابیس‌های واقعی را بازنویسی می‌کند؛ یا دامپ تک‌دیتابیسی بگیرید یا کل دامپ را روی سرور موقت برگردانید.

بعد از استخراج، فقط به «خطا نداد» راضی نشوید: چند فایل مهم را باز کنید و تعداد ردیف چند جدول کلیدی را با SELECT COUNT(*) مقایسه کنید. تست واقعی اما یک قدم جلوتر است: یک سرور ابری ساعتی بسازید، بکاپ را رویش ریستور کنید و ببینید سایت بالا می‌آید یا نه؛ بعد سرور را حذف کنید، چون خاموش‌کردنش هزینه را متوقف نمی‌کند. همین تمرین مهارت روز حادثه را هم می‌سازد: ترتیب کارها تقریباً همان چیزی است که در راهنمای انتقال سایت به هاست جدید آمده، فقط مبدأ به‌جای یک سرور سالم، یک آرشیو است.

💡 نکته: تاریخ آخرین تست ریستور موفق را یادداشت کنید. اگر بیش از یک ماه گذشته، بکاپ‌تان رسماً در وضعیت «امیدواریم» است.

وقتی بکاپ بی‌سروصدا شکست می‌خورد

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

نشانهعلت محتملکار بعدی
فایل جدیدی ساخته نشده و لاگ خالی استکرون اجرا نکرده — مسیر نسبی باینریلاگ سیستم را برای ورودی CRON ببینید و مسیر کامل بنویسید
آرشیو ساخته شده ولی چند کیلوبایت استtar وسط کار به خطا خوردهset -euo pipefail را اضافه و gzip -t را بررسی کنید
دیسک پر شد و سایت از کار افتادسیاست نگهداری اجرا نشدهبا df -h فضا را ببینید و خط find را تست کنید
فایل‌ها برگشتند اما سایت خطای ۵۰۰ می‌دهدمالکیت و سطح دسترسی بازنگشتهریستور را با کاربر ریشه و tar -xzpf تکرار کنید
دامپ ریستور می‌شود ولی رویه‌ها نیستندرویه‌ها و رویدادها دامپ نشده‌اند--routines و --events را اضافه کنید
بکاپ‌های مقصد ناگهان ناپدید شده‌اند--delete یا کلید SSH بدون محدودیتکلید را با restrict,command ببندید و مدل را به pull ببرید
ارتقای سرور، بکاپ شبانه را از کار انداختتغییر نام mysqldump به mariadb-dumpاسکریپت را به‌روز و یک بار دستی اجرا کنید

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

بکاپ روی هاست اشتراکی و سرور ابری

اگر سایت‌تان روی هاست اشتراکی است، بیشتر این مقاله شکل ساده‌تری پیدا می‌کند ولی حذف نمی‌شود. بخش پشتیبان‌گیری پنل یک نسخه‌ی کامل از فایل‌ها و دیتابیس می‌سازد که می‌توانید دانلودش کنید؛ همین کار در پنل فارسی مهران هاست هم در دسترس است. اما بکاپی که فقط روی همان هاست بماند هنوز صفر نسخه‌ی بیرونی دارد. و اگر وردپرس دارید، wp-config.php و پوشه‌ی wp-content/uploads دو دارایی غیرقابل‌بازسازی‌اند؛ هسته و افزونه‌ها هر لحظه دوباره نصب می‌شوند.

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

سؤالات پرتکرار

هر چند وقت یک بار باید از سرور لینوکس بکاپ بگیرم؟

فاصله‌ی بکاپ باید برابر با حداکثر داده‌ای باشد که از دست‌رفتنش را می‌پذیرید. برای بیشتر سایت‌ها یک بکاپ شبانه در ساعت کم‌ترافیک کافی است، چون در بدترین حالت یک روز کار از دست می‌رود. برای فروشگاه‌های آنلاین و سامانه‌های تراکنشی، دیتابیس باید هر چند ساعت بکاپ شود در حالی که فایل‌های سایت می‌توانند همچنان شبانه بمانند. عدد را از نیاز کسب‌وکار بیرون بکشید، نه از عادت.

تفاوت بکاپ کامل، افزایشی و تفاضلی چیست؟

بکاپ کامل هر بار همه‌ی داده را از نو ذخیره می‌کند: بزرگ‌ترین حجم، ساده‌ترین ریستور. بکاپ افزایشی فقط تغییرات نسبت به آخرین بکاپ را نگه می‌دارد، پس کوچک و سریع است اما ریستورش به زنجیره‌ی کاملی از نسخه‌ها وابسته است. بکاپ تفاضلی تغییرات نسبت به آخرین بکاپ کامل را ذخیره می‌کند و حد وسط این دوست. ابزارهایی مثل restic این پیچیدگی را پنهان می‌کنند: ذخیره افزایشی است ولی هر اسنپ‌شات مستقل بازیابی می‌شود.

چرا نباید پوشه‌ی /var/lib/mysql را مستقیم کپی کرد؟

چون دیتابیسِ در حال کار، داده را بین حافظه و دیسک در جریان دارد و کپی فایلی از آن یک وضعیت نیمه‌کاره و ناسازگار ثبت می‌کند که اغلب اصلاً بالا نمی‌آید. راه درست، دامپ منطقی با ابزار خود دیتابیس است: در MySQL و MariaDB با سوییچ --single-transaction که برای جدول‌های InnoDB بدون قفل‌کردن سایت نمای سازگار می‌گیرد، و در PostgreSQL با pg_dump.

بکاپ ارائه‌دهنده کافی نیست؟

کافی نیست، چون اسنپ‌شات ارائه‌دهنده در همان زیرساختی نگه‌داری می‌شود که سرور شما در آن است و بند «یک نسخه بیرون از سرور» را برآورده نمی‌کند. دو محدودیت عملی هم دارد: معمولاً کل دیسک را بازمی‌گرداند و برای برگرداندن یک فایل مناسب نیست، و در هر موقعیتی در دسترس نیست. بهترین کار، استفاده از آن به‌عنوان لایه‌ی اول است.

چطور بکاپ‌هایم را از دسترس باج‌افزار دور نگه دارم؟

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

آموزش‌های مرتبط

آماده‌ی تمرین عملی هستید؟

سرور ابری ساعتی مهران هاست در ۶۰ ثانیه تحویل می‌شود — تمرین کنید و فقط بابت همان ساعت‌ها پرداخت کنید. هزینه را پیش از ثبت‌نام با محاسبه‌گر برآورد کنید.