اتصال کلاینت mc مینیو به آبجکت استوریج S3
راهاندازی mc از صفر: ساخت alias با endpoint و کلید دسترسی، تفاوت mc cp با mc mirror، آدرسدهی path-style برای سرویسهای غیر AWS و امن کردن فایل ~/.mc/config.json.
اتصال mc به آبجکت استوریج در چند دقیقه
کلاینت mc مینیو یک فایل اجرایی تکتکه است که با هر سرویس سازگار با S3 حرف میزند. تمام کار راهاندازی در یک دستور خلاصه میشود: با mc alias set یک نام مستعار میسازید که آدرس endpoint و جفت کلید دسترسی شما را نگه میدارد، و از آن به بعد هر دستور دیگری با همان نام کوتاه کار میکند. اگر باکت را از قبل دارید، ده دقیقه وقت لازم است.
این راهنما فرض میکند فضای ذخیرهسازی آماده است: یک باکت روی سرویس سازگار با S3 یکی از سرویسدهندههای داخلی، یا یک سرور MinIO که خودتان روی VPS بالا آوردهاید. کاری که اینجا انجام میدهیم، وصل کردن ماشین خودتان به آن باکت است و بعد جابهجا کردن درست داده بین این دو.
نصب mc روی لینوکس، مک و ویندوز
mc در مخازن apt یا dnf نیست. یک باینری استاتیک است که مستقیم دانلود میکنید و هیچ وابستگی دیگری ندارد.
curl -O https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/mc
mc --versionروی پردازنده ARM (مثلاً یک VPS مبتنی بر Ampere یا لپتاپ اپل با لینوکس) به جای linux-amd64 از linux-arm64 استفاده کنید. روی مکاواس اگر Homebrew دارید brew install minio/stable/mc کوتاهترین راه است. روی ویندوز فایل mc.exe را از مسیر windows-amd64 دانلود کنید و از PowerShell صدا بزنید.
mc --version باید شماره نسخه را چاپ کند. اگر به جای آن یک رابط دو ستونی تمامصفحه باز شد، برنامه دیگری اجرا شده است: روی خیلی از توزیعهای لینوکس بستهای به نام mc وجود دارد که Midnight Commander است، یک فایلمنیجر متنی و کاملاً بیربط به مینیو. اگر آن بسته نصب است، نام باینری مینیو را mcli بگذارید یا همیشه مسیر کامل /usr/local/bin/mc را بنویسید. دلیل برخورد ساده است: هر دو برنامه یک نام اجرایی را ادعا میکنند و اولین مورد در PATH برنده میشود. با which -a mc میبینید کدامها نصباند.
سه چیزی که باید از پنل سرویسدهنده بردارید
برای ساختن alias دقیقاً به سه مقدار نیاز دارید. نام این سه مقدار در پنلهای مختلف فرق میکند، پس به جای دنبال کردن یک عنوان ثابت، دنبال شکل آنها بگردید.
آدرس endpoint. یک آدرس https:// که فقط میزبان سرویس است، بدون نام باکت و بدون مسیر. نام باکت را در دستورهای mc مینویسید، نه در endpoint. اگر باکت را داخل آدرس بگذارید، mc آن را بخشی از نام میزبان یا مسیر پایه میفهمد و هیچکدام از دستورهای بعدی به مقصد درست نمیرسند.
کلید دسترسی (access key) و کلید مخفی (secret key). این جفت در پنل زیر عنوانهایی مثل Access Key یا S3 Credentials ساخته میشود. کلید مخفی معمولاً فقط یک بار نمایش داده میشود، پس همان لحظه ذخیرهاش کنید. اگر گمش کردید، کلید قبلی را باطل و یک جفت تازه بسازید.
رشته منطقه (region)، اگر سرویس اعلامش کرده باشد. mc در بیشتر موارد منطقه را خودش از سرویس میپرسد و شما کاری ندارید. اما دستورهایی مثل mc mb و mc mirror پرچم --region دارند و کلاینتهای دیگر مثل aws-cli یا rclone معمولاً یک رشته منطقه اجباری میخواهند. وقتی سرویس رشته خاصی اعلام نکرده باشد، us-east-1 مقداری است که بیشتر پیادهسازیهای سازگار با S3 قبول میکنند.
پنل سرویسدهندههای داخلی مثل ArvanCloud یا ParsPack یا لیارا هرکدام چیدمان خودشان را دارند و مستندات آنها مرجع نهایی است. چیزی که ثابت میماند شکل این سه مقدار است، نه جای دکمهها.
ساخت alias با mc alias set
mc alias set myobj https://s3.example.com ACCESS_KEY SECRET_KEY
mc alias list
mc ls myobjترتیب آرگومانها ثابت است: نام مستعار، آدرس endpoint، کلید دسترسی، کلید مخفی. نام مستعار فقط حروف و رقم و خط تیره و زیرخط میپذیرد و باید با یک حرف شروع شود. به بزرگی و کوچکی حروف هم حساس است، پس myobj و MyObj دو alias جدا هستند.
mc ls myobj فهرست باکتهای در دسترس آن کلید را میدهد و همین اولین آزمون واقعی اتصال است. اگر فهرست خالی برگشت ولی در پنل باکت دارید، یعنی اتصال برقرار شده اما آن کلید به آن باکت دسترسی ندارد. اگر دستور با خطا برگشت، به بخش بعدی بروید.
برای پاک کردن یک alias از mc alias remove myobj استفاده کنید. توجه کنید که این کار فقط ورودی سمت کلاینت شما را پاک میکند و کلید هنوز روی سرویس معتبر است. ابطال واقعی کلید فقط در پنل سرویسدهنده انجام میشود.
چرا اتصال به سرویسهای غیر AWS شکست میخورد
دو شکل آدرسدهی برای باکتها وجود دارد. در حالت virtual-host نام باکت زیردامنه endpoint میشود، یعنی چیزی شبیه mybucket.s3.example.com. در حالت path-style نام باکت اولین جزء مسیر است، یعنی s3.example.com/mybucket. mc به صورت پیشفرض با --path auto خودش تصمیم میگیرد.
این تصمیم خودکار وقتی خراب میشود که سرویس گواهی TLS با دامنه جایگزین (wildcard) نداشته باشد یا DNS برای زیردامنه باکت جوابی ندهد. در آن حالت درخواست یا به خطای گواهی میخورد یا اصلاً میزبان را پیدا نمیکند. راهحل این است که حالت را صریح اعلام کنید.
mc alias set myobj https://s3.example.com ACCESS_KEY SECRET_KEY --api S3v4 --path on--path on یعنی همیشه path-style، --path off یعنی همیشه virtual-host و auto همان پیشفرض است. --api هم روش محاسبه امضا را تعیین میکند: S3v4 پیشفرض و گزینه درست است، و S3v2 منسوخ شده و فقط برای سرویسهای خیلی قدیمی معنا دارد.
سه خطای رایج دیگر و علت واقعیشان:
- خطایی که به امضای درخواست اشاره میکند، تقریباً همیشه یعنی کلید مخفی ناقص کپی شده است. یک کاراکتر جاافتاده یا یک فاصله اضافه در انتهای رشته کافی است، چون امضا روی کل کلید محاسبه میشود.
- اگر امضا درست است و باز هم رد میشود، ساعت ماشین را ببینید. امضای نسخه چهار S3 مهر زمان درخواست را در خودش دارد و سرور درخواستی را که بیش از حدود ۱۵ دقیقه با ساعت خودش فاصله دارد رد میکند.
timedatectlوضعیت همگامسازی را نشان میدهد و نصبchronyمشکل را برای همیشه حل میکند. - اگر سرویس گواهی خودامضا دارد، mc اتصال را قطع میکند. پرچم
--insecureبررسی گواهی را خاموش میکند و برای تست یکباره قابل قبول است، ولی راه درست این است که گواهی CA خودتان را به فروشگاه اعتماد سیستم اضافه کنید تا هر ابزار دیگری هم بدون پرچم خطرناک کار کند.
دیدن باکتها: ls و du و stat
mc ls myobj
mc ls myobj/mybucket
mc ls --recursive myobj/mybucket/logs/
mc du myobj/mybucket
mc stat myobj/mybucket/report.pdf
mc mb myobj/newbucketmc ls بدون مسیر باکتها را فهرست میکند و با مسیر، محتوای همان پیشوند را. --recursive کل درخت زیر یک پیشوند را باز میکند و روی باکتهای بزرگ میتواند طولانی شود. mc du حجم و تعداد آبجکت را جمع میزند، که تنها راه سریع فهمیدن این است که صورتحساب ماهانهتان از کجا میآید. اگر هنوز دارید بین گزینهها انتخاب میکنید، مقایسه هزینه استوریج VPS و بلاک و آبجکت همین عدد را به قیمت وصل میکند.
mc stat متادیتای یک آبجکت را میدهد: اندازه، تاریخ تغییر، نوع محتوا و تگها. وقتی فایلی در مرورگر درست دانلود نمیشود، معمولاً Content-Type اشتباه در همین خروجی دیده میشود.
mc cp یا mc mirror؟ تفاوت اصلی در اجرای دوم است
mc cp یک کپی یکطرفه از چیزی است که نامش را بردهاید. mc mirror یک همگامسازی درخت است که مبدأ و مقصد را مقایسه میکند. تا وقتی دستور را فقط یک بار اجرا میکنید تفاوت زیادی حس نمیشود. تفاوت در اجرای دوم خودش را نشان میدهد.
mc cp ./report.pdf myobj/mybucket/report.pdf
mc cp --recursive ./site/ myobj/mybucket/site/
mc cp myobj/mybucket/report.pdf ./mc cp هر چیزی را که نام ببرید دوباره میفرستد، حتی اگر همان نسخه در مقصد باشد، چون کارش مقایسه نیست. برای ۱۰ گیگابایت عکس که فقط دو فایلش عوض شده، یعنی دوباره ۱۰ گیگابایت ترافیک خروجی از ماشین شما.
mc mirror --dry-run ./site/ myobj/mybucket/site/
mc mirror ./site/ myobj/mybucket/site/mc mirror فهرست هر دو سر را میگیرد و فقط چیزی را میفرستد که در مقصد نیست. اجرای دوم روی داده بدون تغییر تقریباً هیچ ترافیکی تولید نمیکند. --dry-run هم بدون انتقال داده نشان میدهد چه چیزی قرار است جابهجا شود، و روی هر دستوری که مقصد را تغییر میدهد ارزش یک بار اجرا شدن را دارد.
یک رفتار پیشفرض هست که خیلیها را غافلگیر میکند: mc mirror بدون --overwrite آبجکتی را که از قبل در مقصد وجود دارد جایگزین نمیکند و برای آن شیء خطا گزارش میکند. یعنی اگر یک فایل را ویرایش کنید و دوباره mirror بزنید، نسخه قدیمی در مقصد سر جایش میماند. این پیشفرض عمدی و محافظهکارانه است، ولی اگر خبر نداشته باشید فکر میکنید همگامسازی کار کرده است.
پرچمهای خطرناک: overwrite و remove و watch
--overwrite: به mirror اجازه میدهد آبجکت موجود در مقصد را با نسخه مبدأ جایگزین کند. برای یک آینه واقعی لازم است و بدون آن، آینه با اولین ویرایش فایل از مبدأ عقب میافتد.--remove: هر چیزی را که در مقصد هست و در مبدأ نیست پاک میکند. این پرچم همان چیزی است که «آینه» را واقعاً آینه میکند، و همان چیزی است که با یک مسیر مبدأ اشتباه، مقصد را خالی میکند. اگر مبدأ را اشتباه بنویسید و آن مسیر خالی باشد، mirror با وفاداری کامل مقصد را هم خالی میکند. قبل از هر اجرای--removeیک بار--dry-runبزنید.--watch: فرآیند را زنده نگه میدارد و تغییرات را دنبال میکند تا وقتی خودتان متوقفش کنید. برای یک پوشه محلی روی همان ماشین منطقی است. برای مبدأ راه دور به رویدادهای سمت سرویس وابسته است و همه سرویسهای سازگار با S3 آن رویدادها را به یک شکل نمیدهند، پس قبل از تکیه کردن روی آن تستش کنید.--summary: در پایان خلاصهای از حجم همگامشده میدهد. برای کارهای زمانبندیشده که لاگشان را بعداً میخوانید مفید است.
نکته عملیاتی درباره --watch: این دستور یک فرآیند بلندمدت است. اگر آن را در یک نشست SSH اجرا کنید، با بسته شدن نشست از بین میرود و هیچ هشداری هم نمیبینید. اگر واقعاً به همگامسازی پیوسته نیاز دارید، آن را به یک سرویس systemd با Restart=always تبدیل کنید. در غیر این صورت یک اجرای زمانبندیشده هر چند ساعت، سادهتر و قابل اتکاتر است.
فایل ~/.mc/config.json یک فایل رمز است
mc alias set کلید دسترسی و کلید مخفی را به صورت متن ساده در ~/.mc/config.json مینویسد. هیچ رمزنگاری و هیچ کلیدواژهای در کار نیست. هر کس بتواند آن فایل را بخواند، کلیدهای شما را دارد.
ls -ld ~/.mc
ls -l ~/.mc/config.json
chmod 700 ~/.mc
chmod 600 ~/.mc/config.jsonروی لپتاپ شخصی این موضوع کماهمیت است. روی یک VPS که چند نفر روی آن حساب دارند اهمیت پیدا میکند، چون umask پیشفرض بعضی سیستمها فایل تازه را برای گروه یا برای همه خواندنی میسازد. دو دستور chmod بالا این را قطعی میکنند. کاربر root همچنان میتواند فایل را بخواند و راهی برای دور زدن این وجود ندارد، پس روی سروری که مدیرش شما نیستید، کلید بلندمدت نگذارید.
کلید لو رفته دقیقاً چه چیزی به مهاجم میدهد؟ خواندن و دانلود همه آبجکتهایی که آن کلید دسترسی دارد، حذف همان آبجکتها، و آپلود داده تازهای که هزینه ذخیرهسازی و ترافیکش را شما پرداخت میکنید. اگر کلید در سطح حساب ساخته شده باشد، ساخت و حذف باکت هم ممکن میشود. به همین دلیل برای هر کار یک کلید جدا با کمترین دسترسی لازم بسازید، اگر پنل سرویس این امکان را میدهد.
یک راه فرار از فایل هم هست: alias موقت از طریق متغیر محیطی.
export MC_HOST_myobj="https://ACCESS_KEY:SECRET_KEY@s3.example.com"
mc ls myobjاین شکل هیچ چیزی روی دیسک نمینویسد و برای اسکریپت و کانتینر مناسب است. دو نکته را جدی بگیرید. اول اینکه کلیدها داخل یک URL هستند، پس اگر کلید شما کاراکترهایی مثل / یا @ یا + دارد باید درصد-انکد شوند وگرنه URL شکسته میشود و خطا به آدرس اشاره میکند نه به کلید. دوم اینکه این خط در تاریخچه شل شما میماند: مقدار را در یک فایل با دسترسی ۶۰۰ نگه دارید و در systemd با EnvironmentFile تحویلش بدهید.
یک هشدار آخر که آسان فراموش میشود: پشتیبان خانگی شما این فایل را هم برمیدارد. اگر آن پشتیبان رمزنگاری نشده باشد، کلیدهای آبجکت استوریج شما همراهش سفر میکنند. رمزنگاری داده روی استوریج قبل از ارسال همین حفره را میبندد.
نسخه دوم روی MinIO خودتان: آینه بین دو سرویس
حالا کاربرد اصلی که ارزش این همه تنظیم را دارد. هر دو سر یک دستور mirror میتوانند alias باشند، نه فقط یکی. یعنی میتوانید محتوای باکت سرویسدهنده را روی MinIO خودتان روی یک VPS دیگر آینه کنید و یک کپی مستقل از سرویس اول داشته باشید.
mc alias set myobj https://s3.example.com ACCESS_KEY SECRET_KEY --path on
mc alias set homelab https://s3.yourdomain.example ACCESS_KEY SECRET_KEY
mc mb homelab/offsite-copy
mc version enable homelab/offsite-copy
mc mirror --dry-run myobj/mybucket homelab/offsite-copy
mc mirror --overwrite --summary --limit-download 20M myobj/mybucket homelab/offsite-copyیک واقعیت مهم درباره مسیر داده: mc یک واسطه است. داده از مبدأ به ماشینی که mc روی آن اجرا میشود میآید و از همانجا به مقصد میرود. اگر این کار را روی لپتاپ خانگی اجرا کنید، به اندازه حجم باکت دانلود و به همان اندازه آپلود میکنید. اجرای همان دستور روی خود VPS مقصد مسیر را کوتاهتر و سریعتر میکند.
--limit-download 20M و --limit-upload 20M نرخ انتقال را محدود میکنند. روی یک VPS که سرویس دیگری هم میدهد این کار لازم است، وگرنه اولین آینهگیری کامل تمام پهنای باند را میگیرد و بقیه سرویسها کند میشوند.
برای اجرای منظم، یک خط cron کافی است:
30 3 * * * /usr/local/bin/mc --config-dir /home/youruser/.mc mirror --overwrite --summary myobj/mybucket homelab/offsite-copy >> /home/youruser/mc-mirror.log 2>&1--config-dir را صریح بنویسید. اگر دستور را با کاربر دیگری یا داخل یک یونیت systemd اجرا کنید، ~ همان مسیری نیست که شما در آن alias ساختید و mc با پیکربندی خالی بالا میآید. هدایت خروجی به یک فایل لاگ هم تنها راهی است که بعداً بفهمید اجرای دیشب موفق بوده یا نه.
و یک مرز که باید روشن باشد: آینه، پشتیبان نیست. آینه یک کپی از وضعیت همین لحظه است. اگر فایلی خراب یا با باجافزار رمز شود و بعد mirror اجرا شود، نسخه خراب هم منتقل میشود، و با --remove حذفها هم به مقصد میروند. mc version enable روی مقصد MinIO نسخههای قبلی آبجکت را نگه میدارد و بخشی از این خطر را کم میکند. برای تاریخچه واقعی و بازیابی نقطهای، به ابزار پشتیبانگیری واقعی نیاز دارید و نوشتن پشتیبان restic در دو مخزن جدا همان جایی است که این راهنما شما را تحویل میدهد.
FAQ
چرا mc وصل نمیشود در حالی که پنل باکت را نشان میدهد؟
به ترتیب این چهار مورد را بررسی کنید. اول، endpoint باید فقط میزبان سرویس باشد، بدون نام باکت در آدرس. دوم، alias را با --path on دوباره بسازید، چون بسیاری از سرویسهای سازگار با S3 آدرسدهی path-style میخواهند و تشخیص خودکار همیشه درست از آب درنمیآید. سوم، ساعت سیستم را با timedatectl ببینید، چون امضای نسخه چهار S3 مهر زمان دارد و اختلاف چند ده دقیقهای باعث رد شدن درخواست میشود. چهارم، مطمئن شوید کلید متعلق به همان حساب و همان باکت است، چون کلید معتبر یک حساب دیگر اتصال را برقرار میکند ولی فهرست خالی میدهد.
تفاوت mc cp و mc mirror در عمل چیست؟
mc cp هر چیزی را که نام ببرید میفرستد، بدون مقایسه با مقصد، پس اجرای دوم دوباره همه حجم را منتقل میکند. mc mirror دو سر را مقایسه میکند و فقط تفاوت را میفرستد، پس برای همگامسازی دورهای همین را میخواهید. حواستان باشد که mc mirror بدون --overwrite فایلهای تغییرکرده را در مقصد جایگزین نمیکند و برای آنها خطا گزارش میکند، یعنی آینهتان بیسروصدا از مبدأ عقب میماند.
فایل ~/.mc/config.json چقدر حساس است؟
خیلی. کلید دسترسی و کلید مخفی همه alias های شما به صورت متن ساده داخلش هستند. با chmod 700 ~/.mc و chmod 600 ~/.mc/config.json دسترسی سایر کاربران ماشین را ببندید. کسی که این فایل را بخواند میتواند همه آبجکتهای در دسترس آن کلید را دانلود یا حذف کند و داده تازهای آپلود کند که هزینهاش را شما میدهید. برای اسکریپتها به جای فایل از متغیر MC_HOST_<alias> استفاده کنید و مقدارش را در یک فایل با دسترسی ۶۰۰ نگه دارید.
آیا mc mirror جای پشتیبانگیری را میگیرد؟
نه. آینه فقط وضعیت فعلی مبدأ را بازتاب میدهد. خرابی فایل و رمزگذاری باجافزاری هم به همان سرعت داده سالم منتقل میشوند، و با --remove حذفهای ناخواسته هم تکرار میشوند. فعال کردن نسخهبندی روی باکت مقصد با mc version enable بخشی از این خطر را میپوشاند، ولی برای بازیابی یک نقطه زمانی مشخص به ابزاری نیاز دارید که اسنپشات و نگهداری تاریخچه بلد باشد.