آموزش راه‌اندازی MinIO روی لینوکس با Docker و SSL (به‌همراه وضعیت فعلی نسخه‌ی Community)

MinIO سال‌ها محبوب‌ترین راه برای داشتن یک Object Storage سازگار با S3 روی سرور شخصی بود: یک فایل اجرایی، یک دستور و تمام. اما قبل از شروع این آموزش باید یک واقعیت مهم را بدانید، چون روی تصمیم شما اثر مستقیم دارد.

وضعیت فعلی MinIO Community (مهم؛ قبل از نصب بخوانید)

در سال‌های ۲۰۲۵ و ۲۰۲۶ شرکت MinIO مسیر نسخه‌ی رایگان را به‌شکل جدی تغییر داد. بر اساس مخزن رسمی github.com/minio/minio در زمان نگارش این مقاله:

  • در README مخزن آمده است که این مخزن دیگر نگه‌داری نمی‌شود و مخزن به حالت Archived (فقط‌خواندنی) درآمده است.
  • فایل‌های اجرایی آماده (Binary) برای نسخه‌ی Community دیگر منتشر نمی‌شوند و باینری‌های قدیمی به‌روزرسانی نمی‌گیرند.
  • ایمیج Docker رسمی جدید هم منتشر نمی‌شود و README توصیه می‌کند ایمیج را خودتان از سورس بسازید.
  • پیش از آن، بخش مدیریتی کنسول وب از نسخه‌ی Community حذف شده بود و کارهای مدیریتی (کاربر، Policy و…) عملاً با ابزار خط فرمان mc انجام می‌شود.
  • مجوز کد منبع همچنان AGPLv3 است. مسیر رسمی شرکت، محصول تجاری AIStor است که نسخه‌ی رایگانِ تک‌نودی با مجوز اختصاصی و نسخه‌ی Enterprise دارد.

یعنی اگر امروز MinIO Community را نصب کنید، نرم‌افزاری را اجرا می‌کنید که وصله‌ی امنیتی جدیدی از سازنده‌ی اصلی دریافت نمی‌کند. فورک‌های جامعه‌محور هم ایجاد شده‌اند (مثلاً پروژه‌ای از تیم Pigsty با ایمیج pgsty/minio)، اما این‌ها پروژه‌های شخص ثالث‌اند و آینده‌شان را باید خودتان ارزیابی کنید. جزئیات این وضعیت ممکن است تغییر کند؛ قبل از تصمیم نهایی، صفحه‌ی مخزن رسمی را بررسی کنید.

توصیه‌ی ما: برای پروژه‌ی جدید و بلندمدت، گزینه‌هایی مثل Ceph RGW یا Garage را هم جدی بررسی کنید (مقاله‌ی مقایسه‌ی MinIO، Ceph و Garage). اگر MinIO را از قبل دارید، یا برای محیط توسعه، تست و بکاپ داخلی یک S3 ساده می‌خواهید، این آموزش روشی امن و قابل‌نگه‌داری برای راه‌اندازی آن را نشان می‌دهد.

پیش‌نیازها

  • یک سرور Ubuntu 24.04 با Docker و پلاگین Docker Compose
  • یک دیسک یا پارتیشن جداگانه برای داده، مثلاً mount شده در /srv/minio
  • دو زیردامنه: s3.example.com برای API و console.example.com برای کنسول وب، که به IP سرور اشاره کنند
  • Nginx و Certbot برای SSL

نکته‌ی سرورهای داخل ایران: دریافت ایمیج‌های پایه (مثل golang و alpine) از Docker Hub روی IP ایران معمولاً با خطای 403 مواجه می‌شود و دانلود ماژول‌های Go هم ممکن است ناپایدار باشد. یا ایمیج را روی یک سرور خارج بسازید و به Registry خصوصی خود منتقل کنید، یا از راه‌حل‌های مقاله‌ی دسترسی به Docker Hub از ایران و یک پراکسی مثل Nexus استفاده کنید.

قدم ۱: ساخت ایمیج MinIO از سورس

چون ایمیج رسمی به‌روز وجود ندارد، ایمیج را خودمان می‌سازیم. مزیت این کار این است که دقیقاً می‌دانید چه چیزی اجرا می‌شود. پوشه‌ی پروژه را بسازید:

sudo mkdir -p /opt/minio/build /srv/minio/data
cd /opt/minio

فایل /opt/minio/build/Dockerfile:

FROM golang:1.25-alpine AS build
ENV CGO_ENABLED=0
# برای تکرارپذیری، به‌جای latest یک commit مشخص را pin کنید
RUN go install github.com/minio/minio@latest
RUN go install github.com/minio/mc@latest

FROM alpine:3.20
RUN apk add --no-cache ca-certificates \
 && adduser -D -H -u 1000 minio
COPY --from=build /go/bin/minio /go/bin/mc /usr/local/bin/
USER minio
EXPOSE 9000 9001
ENTRYPOINT ["minio"]

نسخه‌ی Go مورد نیاز را README مخزن مشخص می‌کند (در زمان نگارش، حداقل Go 1.24). اگر ساخت با خطای نسخه متوقف شد، تگ ایمیج golang را به‌روز کنید. ابزار mc را هم در همین ایمیج قرار دادیم تا برای مدیریت، چیز دیگری نصب نکنید.

قدم ۲: فایل‌های Compose و متغیرهای محیطی

اطلاعات ورود را هرگز داخل فایل Compose ننویسید. فایل /opt/minio/.env:

MINIO_ROOT_USER=minio-admin
MINIO_ROOT_PASSWORD=یک-رمز-طولانی-و-تصادفی
MINIO_SERVER_URL=https://s3.example.com
MINIO_BROWSER_REDIRECT_URL=https://console.example.com

یک رمز قوی تولید کنید و دسترسی فایل را محدود کنید:

openssl rand -base64 30
sudo chmod 600 /opt/minio/.env
sudo chown -R 1000:1000 /srv/minio/data

فایل /opt/minio/docker-compose.yml:

services:
  minio:
    build: ./build
    image: minio-local:2026
    container_name: minio
    restart: unless-stopped
    command: server /data --console-address ":9001"
    env_file: .env
    ports:
      - "127.0.0.1:9000:9000"   # S3 API
      - "127.0.0.1:9001:9001"   # کنسول وب
    volumes:
      - /srv/minio/data:/data
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:9000/minio/health/live"]
      interval: 30s
      timeout: 5s
      retries: 3

پورت‌ها فقط روی 127.0.0.1 باز شده‌اند تا تنها راه دسترسی از بیرون، Reverse Proxy با SSL باشد. ساخت و اجرا:

cd /opt/minio
docker compose build
docker compose up -d
docker compose ps
docker compose logs -f minio

قدم ۳: Nginx و SSL

ابتدا گواهی بگیرید:

sudo apt install -y nginx certbot python3-certbot-nginx
sudo certbot certonly --nginx -d s3.example.com -d console.example.com

فایل /etc/nginx/sites-available/minio:

server {
    listen 443 ssl;
    http2 on;
    server_name s3.example.com;
    ssl_certificate     /etc/letsencrypt/live/s3.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/s3.example.com/privkey.pem;

    client_max_body_size 0;
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        chunked_transfer_encoding off;
        proxy_pass http://127.0.0.1:9000;
    }
}

server {
    listen 443 ssl;
    http2 on;
    server_name console.example.com;
    ssl_certificate     /etc/letsencrypt/live/s3.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/s3.example.com/privkey.pem;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass http://127.0.0.1:9001;
    }
}
sudo ln -s /etc/nginx/sites-available/minio /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

دو نکته حیاتی است: proxy_set_header Host $http_host باید دقیقاً همان Host درخواست را منتقل کند، وگرنه امضای درخواست‌های S3 نامعتبر می‌شود و خطای SignatureDoesNotMatch می‌گیرید. client_max_body_size 0 هم محدودیت حجم آپلود Nginx را برمی‌دارد.

قدم ۴: ساخت Bucket، کاربر و Policy با mc

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

docker compose exec minio sh
mc alias set local http://127.0.0.1:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"
mc admin info local

یک Bucket برای فایل‌های اپلیکیشن بسازید:

mc mb local/app-uploads

یک Policy که فقط به همین Bucket دسترسی می‌دهد. فایل /tmp/app-rw.json را داخل کانتینر بسازید:

cat > /tmp/app-rw.json <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket", "s3:GetBucketLocation"],
      "Resource": ["arn:aws:s3:::app-uploads"]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": ["arn:aws:s3:::app-uploads/*"]
    }
  ]
}
EOF

Policy را ثبت کنید، کاربر را بسازید و Policy را به آن متصل کنید:

mc admin policy create local app-rw /tmp/app-rw.json
mc admin user add local app-user 'رمز-قوی-برای-اپلیکیشن'
mc admin policy attach local app-rw --user app-user
mc admin user info local app-user

حالا از سیستم خودتان با کلید app-user تست کنید:

mc alias set myapp https://s3.example.com app-user 'رمز-قوی-برای-اپلیکیشن'
mc cp ./test.jpg myapp/app-uploads/
mc ls myapp/app-uploads/
mc mb myapp/another-bucket   # باید با Access Denied رد شود

اگر می‌خواهید فایل‌های یک Prefix به‌صورت عمومی قابل دانلود باشند (مثلاً تصاویر سایت)، فقط همان Prefix را عمومی کنید، نه کل Bucket:

mc anonymous set download local/app-uploads/public

نکات محیط Production

  • تک‌دیسک یعنی بدون افزونگی: در حالت تک‌نود و تک‌دیسک، MinIO از Erasure Coding استفاده نمی‌کند و قابلیت‌هایی مثل Versioning و Object Lock در دسترس نیستند. برای داده‌ی مهم، حداقل چند دیسک (حالت تک‌نود چند‌دیسکی) یا کلاستر چندنودی لازم است و حتی آن هم جایگزین بکاپ نیست.
  • فایل‌سیستم: برای دیسک داده XFS توصیه‌ی رایج است. دیسک‌ها را با RAID سخت‌افزاری ترکیب نکنید اگر قرار است Erasure Coding خود MinIO افزونگی را مدیریت کند.
  • به‌روزرسانی و امنیت: چون نسخه‌ی Community دیگر وصله‌ی رسمی نمی‌گیرد، API را فقط در حد لازم در معرض اینترنت قرار دهید، کنسول را پشت فایروال یا VPN ببرید و برنامه‌ای برای مهاجرت در صورت کشف آسیب‌پذیری داشته باشید.
  • مانیتورینگ: MinIO متریک‌های Prometheus ارائه می‌دهد. آن را به داشبورد خود وصل کنید (مقاله‌ی مانیتورینگ با Prometheus و Grafana) و برای پر شدن دیسک هشدار بگذارید.
  • بکاپ از خود Object Storage: Object Storage روی یک سرور، بکاپ خودش نیست. با mc mirror یا rclone یک نسخه روی سرور یا دیتاسنتر دیگر نگه دارید.
  • کلیدها: کلید root را در هیچ اپلیکیشنی استفاده نکنید و کلیدهای اپلیکیشن را دوره‌ای عوض کنید.

قدم بعدی

حالا یک Endpoint سازگار با S3 دارید. می‌توانید بکاپ خودکار سرور و دیتابیس را با Restic روی آن بفرستید یا فایل‌های آپلود وردپرس و لاراول را به آن منتقل کنید.

جمع‌بندی

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

نمی‌خواهید این کار را خودتان انجام دهید؟ تیم مروانت بر اساس حجم داده و نیاز شما، راهکار مناسب (MinIO، Ceph یا Garage) را انتخاب، راه‌اندازی و نگه‌داری می‌کند. صفحه‌ی راه‌اندازی Object Storage اختصاصی را ببینید.

دیدگاهتان را بنویسید

جستجو

فهرست مطالب