نحوه انتقال فایل از طریق SSH و دستور wget

نحوه انتقال فایل از طریق SSH و دستور wget

حدود ۱۰ دقیقه مطالعه

برای انتقال فایل به سرور از طریق SSH، در بیشتر موارد یکی از این سه ابزار کارتان را راه می‌اندازد: scp برای کپی ساده و یک‌باره، rsync برای حجم‌های بزرگ یا انتقال‌های تکرارشونده، و sftp برای کار تعاملی و فایل‌به‌فایل. اما اگر فایل از قبل روی یک آدرس اینترنتی قرار دارد و می‌خواهید مستقیم داخل خود سرور دانلود شود، ابزار درست wget یا curl است، نه scp. همین wget است که کار انتقال کل محتوای یک اکانت FTP به سرور جدید را هم با یک دستور انجام می‌دهد؛ سناریویی که پایین‌تر در بخش مربوط به اکانت FTP آمده است.

تفاوت اصلی همین‌جاست: scp و rsync و sftp فایل را از کامپیوتر شما به سرور می‌برند و ترافیک از اینترنت خانگی یا اداری شما عبور می‌کند؛ در مقابل wget و curl فایل را از یک URL و با پهنای باند خودِ سرور می‌گیرند. برای فایلی چندگیگابایتی که روی یک مخزن یا فضای ابری موجود است، روش دوم معمولاً به‌مراتب سریع‌تر تمام می‌شود.

پیش‌نیاز: یک دسترسی SSH سالم

همه این روش‌ها روی پوسته امن (SSH) سوار می‌شوند، پس باید نام کاربری، آی‌پی یا دامنه و پورت SSH را در اختیار داشته باشید. پورت پیش‌فرض ۲۲ است، ولی بسیاری از مدیران سرور آن را تغییر می‌دهند و دادن پورت اشتباه به خطای اتصال ختم می‌شود. روی یک VPS یا سرور اختصاصی معمولاً دسترسی کامل شل در اختیار خودتان است و هر چهار ابزار بالا کار می‌کنند.

scp؛ ساده‌ترین راه کپی کردن

scp دقیقاً مثل دستور cp عمل می‌کند، با این تفاوت که یک سرِ مسیر روی ماشین دیگری است:

scp /home/user/backup.tar.gz root@203.0.113.10:/root/

اگر پورت SSH پیش‌فرض نیست، آن را با -P بدهید. حواستان باشد که در scp حرف پورت بزرگ است و در خود ssh کوچک؛ این یکی از رایج‌ترین اشتباه‌هاست:

scp -P 2222 backup.tar.gz root@203.0.113.10:/root/

برای یک پوشه از -r استفاده کنید و برای گرفتن فایل از سرور، فقط جای مبدأ و مقصد را عوض کنید:

scp -r ./public_html root@203.0.113.10:/var/www/
scp root@203.0.113.10:/root/backup.tar.gz .

سوئیچ -p کوچک زمان و سطح دسترسی فایل را حفظ می‌کند. یک نکته فنی: در OpenSSH نسخه ۹ به بعد، scp پشت صحنه از پروتکل SFTP استفاده می‌کند؛ خط فرمان همان است ولی رفتار آن در برخی حالت‌های خاص با گذشته فرق دارد.

rsync؛ انتخاب درست برای حجم زیاد

هر جا انتقال بیش از چند صد مگابایت است یا قرار است چند بار تکرار شود، rsync گزینه بهتری است؛ چون فقط تفاوت‌ها را می‌فرستد و اگر ارتباط قطع شود، اجرای دوباره همان دستور کار را از جایی که مانده ادامه می‌دهد:

rsync -avzP -e "ssh -p 2222" /home/user/site/ root@203.0.113.10:/var/www/site/

در این دستور -a حالت آرشیو است (حفظ مجوزها، زمان‌ها و لینک‌های نمادین)، -v گزارش کار می‌دهد، -z داده را حین انتقال فشرده می‌کند و -P ترکیبی از نمایش پیشرفت و نگه‌داشتن فایل ناتمام است. اگر فایل‌ها از قبل فشرده‌اند (مثل tar.gz یا تصاویر)، -z فقط پردازنده را مشغول می‌کند و سودی ندارد.

به اسلش انتهای مسیر مبدأ دقت کنید: site/ یعنی «محتویات پوشه» و site بدون اسلش یعنی «خود پوشه» که داخل مقصد ساخته می‌شود. همچنین پیش از هر اجرای جدی، یک بار با --dry-run نتیجه را ببینید. سوئیچ --delete هر فایلی را که در مبدأ نباشد از مقصد پاک می‌کند؛ این گزینه برگشت‌ناپذیر است و بدون آزمایش با --dry-run نباید اجرا شود.

sftp؛ وقتی می‌خواهید تعاملی جلو بروید

اگر نمی‌دانید دقیقاً چه فایلی کجاست و می‌خواهید بگردید، sftp روی همان کانال SSH یک محیط تعاملی می‌دهد:

sftp -P 2222 root@203.0.113.10

داخل آن با ls و cd در سرور و با lcd در سیستم خودتان جابه‌جا می‌شوید، با put فایل می‌فرستید و با get می‌گیرید. اگر انتقالی نیمه‌کاره ماند، reput و reget آن را ادامه می‌دهند. روی هاست اشتراکی معمولاً به‌جای شل کامل، همین SFTP یا فایل‌منیجر کنترل‌پنل ابزار اصلی شماست و دامنه دسترسی بسته به پلن و سیاست سرویس‌دهنده فرق می‌کند.

wget و curl؛ گرفتن فایل از روی یک آدرس

وقتی فایل روی یک URL در دسترس است، وارد SSH شوید و مستقیم روی سرور دانلود کنید:

wget https://example.com/phpini.txt

با -O می‌توانید نام و مسیر خروجی را تعیین کنید، با -c دانلود نیمه‌تمام را ادامه دهید و با --limit-rate جلوی اشباع‌شدن پهنای باند سرور را بگیرید:

wget -c --limit-rate=5m -O /root/big.iso https://example.com/big.iso

curl هم همین کار را می‌کند؛ -L ریدایرکت‌ها را دنبال می‌کند، -O فایل را با نام اصلی ذخیره می‌کند و -C - ادامه دانلود است:

curl -C - -L -O https://example.com/big.iso

ادامه دادن دانلود فقط وقتی ممکن است که سرور مقابل از درخواست‌های Range پشتیبانی کند؛ در غیر این صورت فایل از ابتدا گرفته می‌شود. بعد از پایان کار هم درستی فایل را با sha256sum big.iso بسنجید و با مقدار منتشرشده مقایسه کنید. یک هشدار امنیتی جدی هم بدهم: خروجی یک آدرس ناشناس را هرگز مستقیم به شل ندهید؛ الگوی «دانلود و اجرای بی‌واسطه اسکریپت» یکی از رایج‌ترین راه‌های آلوده شدن سرور است؛ برای پیدا کردن شل‌های جاسازی‌شده روی سرور هم اسکن فایل‌های آلوده با آنتی‌شلر کمک می‌کند. اگر کار اصلی‌تان ارائه فایل‌های حجیم برای دانلود کاربران است، سرویس‌های تخصصی مثل دانلود هاست از این جهت مناسب‌تر از هاست عمومی هستند.

گرفتن کل محتوای یک اکانت FTP با یک دستور

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

wget -m ftp://Username:Password@203.0.113.20

دقت کنید آدرسی که در این دستور می‌نویسید آی‌پی مبدأ است، یعنی همان هاست قدیمی که فایل‌ها روی آن هستند؛ دستور را روی سرور مقصد اجرا می‌کنید و اطلاعات ورود هم مال اکانت FTP مبدأ است. سوئیچ -m یعنی حالت mirror و در wget معادل -r -N -l inf --no-remove-listing است: دریافت بازگشتی بدون محدودیت عمق، حفظ زمان فایل‌ها و نگه‌داشتن فایل‌های فهرست پوشه. نتیجه یک کپی کامل از پوشه‌ها و فایل‌های اکانت مبدأ است و چون به لطف -N اجرای دوم فقط فایل‌های تغییرکرده را می‌گیرد، می‌توانید یک بار زودتر همگام‌سازی کنید و درست پیش از تعویض DNS یک بار دیگر همان دستور را بزنید.

این شکلِ دستور برای یک تست سریع خوب است، ولی رمز را در معرض دید می‌گذارد. پیش از اجرای جدی، سه نکته بعدی را بخوانید.

سه نکته‌ای که این دستور را امن و قابل‌اعتماد می‌کند

رمز را داخل خط فرمان ننویسید. هر کاربر دیگری روی سرور با یک ps aux می‌تواند رمز اکانت FTP شما را ببیند و همان رشته در ~/.bash_history هم ثبت می‌شود. راه درست این است که اطلاعات ورود را در فایل ~/.netrc بگذارید. فایل را با ویرایشگر (مثلاً nano ~/.netrc) بسازید و این سه خط را داخلش بنویسید:

machine 203.0.113.20
login Username
password YourPassword

بعد دسترسی فایل را ببندید و دستور را بدون رمز اجرا کنید:

chmod 600 ~/.netrc
wget -m ftp://203.0.113.20

این کار یک مشکل دوم را هم حل می‌کند: اگر رمز شما کاراکترهایی مثل @، :، / یا # داشته باشد، داخل URL باید به شکل درصدی (percent-encoding) نوشته شود وگرنه wget آدرس را اشتباه تفسیر می‌کند؛ در ~/.netrc رمز عیناً نوشته می‌شود. بعد از پایان مهاجرت هم فایل را پاک کنید.

FTP ساده رمزنگاری ندارد. نام کاربری، رمز و خودِ فایل‌ها به‌صورت متن ساده روی شبکه می‌روند. اگر هاست مبدأ FTPS را پشتیبانی می‌کند از آدرس ftps:// استفاده کنید — نسخه‌های جدید wget از آن پشتیبانی می‌کنند و اگر در خروجی wget --help بخش گزینه‌های FTPS را دیدید، یعنی نسخه نصب‌شده روی سرور شما با پشتیبانی SSL ساخته شده است. اگر مبدأ SSH دارد، اصلاً سراغ FTP نروید و کار را با rsync انجام دهید که هم رمزنگاری‌شده است و هم مجوزها را حفظ می‌کند.

محل ذخیره و فایل‌های مخفی را کنترل کنید. به‌صورت پیش‌فرض wget همه چیز را داخل پوشه‌ای هم‌نام میزبان (مثلاً 203.0.113.20/) می‌ریزد. با -nH این پوشه ساخته نمی‌شود، با -P مقصد را تعیین می‌کنید و با --cut-dirs چند سطح ابتدایی مسیر را حذف می‌کنید:

wget -m -nH --cut-dirs=1 -P /var/www/site --limit-rate=5m ftp://203.0.113.20/public_html/

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

find /var/www/site -name '.listing' -type f -delete

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

lftp؛ وقتی حجم زیاد است

برای اکانت‌های بزرگ یا هزاران فایل کوچک، lftp از wget بهتر جواب می‌دهد چون چند فایل را هم‌زمان می‌گیرد و انتقال ناتمام را ادامه می‌دهد. با -u Username (بدون رمز) وارد شوید تا رمز را به‌صورت تعاملی بپرسد و در تاریخچه شل ثبت نشود:

lftp -u Username 203.0.113.20

حالا داخل محیط خود lftp هستید و دستور بعدی را همان‌جا (نه در شل لینوکس) می‌زنید:

mirror --continue --parallel=4 /public_html /var/www/site

همین دستور mirror با سوئیچ -R جهت را برعکس می‌کند، یعنی محتوای پوشه محلی را روی سرور FTP آپلود می‌کند — برای وقتی که مقصد شما هاست FTP است. اگر مبدأ FTPS دارد، پیش از mirror دستور set ftp:ssl-force true را بزنید.

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

بعد از انتقال: مالکیت و سطح دسترسی را اصلاح کنید

این مرحله بیشترین خطاها را می‌سازد. فایلی که با wget و به‌عنوان root گرفته‌اید مالکش root است و وب‌سرور نمی‌تواند آن را بخواند یا در کنارش بنویسد. پس مالکیت را به کاربر درست بدهید (نام کاربر بسته به توزیع، وب‌سرور و کنترل‌پنل فرق می‌کند؛ در دبیان و اوبونتو معمولاً www-data، در خانواده RHEL مثل AlmaLinux و Rocky اغلب apache و با nginx معمولاً nginx است؛ روی سرورهای کنترل‌پنل‌دار هم مالک، کاربر همان اکانت است). پیش از اجرا نام کاربر واقعی وب‌سرور خود را با ps aux | grep -E 'apache|httpd|nginx|php-fpm' بررسی کنید و مسیر را هم دقیق بدهید، چون chown -R روی مسیر اشتباه می‌تواند دسترسی بخش دیگری از سرور را خراب کند:

chown -R www-data:www-data /var/www/site

سپس سطح دسترسی متعارف را اعمال کنید — پوشه‌ها ۷۵۵ و فایل‌ها ۶۴۴:

find /var/www/site -type d -exec chmod 755 {} +
find /var/www/site -type f -exec chmod 644 {} +

اگر جایی شکل قدیمی‌تر این دستور را با -exec chmod 755 {} ; دیدید، آن هم درست است به شرط اینکه سمی‌کالن با بک‌اسلش محافظت شده باشد (یا داخل کوتیشن نوشته شود)؛ بدون بک‌اسلش، شل سمی‌کالن را به‌عنوان جداکننده دستور برمی‌دارد و find با خطای «آرگومان ناقص برای ‎-exec‎» متوقف می‌شود. شکل {} + علاوه بر اینکه این دردسر را ندارد، به‌جای یک اجرای chmod برای هر فایل، فایل‌ها را دسته‌ای پردازش می‌کند و روی پوشه‌های بزرگ به‌مراتب سریع‌تر است.

هرگز برای «حل شدن سریع مشکل» دستور chmod -R 777 نزنید؛ این کار فایل‌ها را برای هر کاربری روی سرور قابل تغییر می‌کند. یادتان باشد rsync -a و scp -p مجوزها را حفظ می‌کنند اما scp ساده، wget و دریافت از FTP این کار را نمی‌کنند. روی سیستم‌هایی که SELinux فعال است، ممکن است به اصلاح برچسب‌های امنیتی با restorecon هم نیاز باشد. اگر سایت بالا نیامد و علتش را پیدا نکردید، بهتر است پیش از آزمون‌وخطا روی سرور زنده از کارشناسان پشتیبانی آنلاین سرور کمک بگیرید.

چند نکته که دردسر را کم می‌کند

  • برای هزاران فایل کوچک، اول آرشیو بگیرید و بعد منتقل کنید؛ سربار هر فایل جداگانه بسیار زیاد است.
  • انتقال‌های طولانی را داخل screen یا tmux اجرا کنید تا قطع شدن اتصال SSH کار را نیمه‌کاره رها نکند؛ برای mirror کردن یک اکانت FTP بزرگ این تقریباً الزامی است.
  • به‌جای رمز عبور از کلید SSH استفاده کنید؛ هم امن‌تر است و هم اسکریپت‌های خودکار را ممکن می‌کند.
  • پیش از جابه‌جایی داده، فضای خالی دیسک مقصد را با df -h بررسی کنید.
  • پس از پایان انتقال، تعداد و حجم فایل‌ها را با find . -type f | wc -l و du -sh در دو طرف مقایسه کنید تا از کامل بودن کار مطمئن شوید.

جمع‌بندی ساده است: از سیستم خودتان به سرور، scp برای کارهای کوچک و rsync برای هر چیز بزرگ‌تر؛ از یک آدرس اینترنتی به سرور، wget یا curl؛ از یک اکانت FTP قدیمی به سرور جدید، wget -m یا mirror در lftp؛ و در پایان همیشه مالکیت و سطح دسترسی را بررسی کنید.

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