How to Install MinIO on Ubuntu 24.04 — Self-Hosted S3-Compatible Object Storage
MinIO turns a plain Ubuntu VPS into a high-performance, S3-compatible object store. It speaks the exact same API that Amazon S3 does, so anything built against the AWS SDK — Terraform, Velero, Restic, boto3, rclone, Kubernetes CSI drivers, Nextcloud, Paperless-ngx, backup tools — can point at your MinIO endpoint with nothing more than a URL and two new credentials. What you get in return is predictable flat-rate storage, full data sovereignty, and no surprise egress bill at the end of the month.
This guide walks through a complete production install on Ubuntu 24.04 LTS: from single-drive development mode, to a proper four-drive Single-Node Multi-Drive (SNMD) deployment with erasure coding, to SSE-KMS encryption with KES, Prometheus metrics, lifecycle rules, and an Nginx TLS reverse proxy in front of it all.
Skip the setup? A tuned Ubuntu 24.04 VPS with 400 GB NVMe is the right foundation for self-hosted object storage. Launch a Professional VPS now and follow along.
Table of Contents
What is MinIO?
MinIO is a high-performance, open-source object storage server written in Go. It implements the Amazon S3 API with a very high level of fidelity — so high that MinIO is frequently used as a drop-in replacement for S3 in local development, CI pipelines, and private-cloud production deployments. Its design goals are simple: speak S3, run anywhere, and saturate the underlying hardware.
MinIO ships as a single static binary with no external database, no ZooKeeper, no etcd, and no managed control plane. State lives on the data drives themselves, encoded with Reed-Solomon erasure coding. You start the binary, point it at one or more drives, and you have object storage. That simplicity is the reason it shows up so often underneath Kubernetes registries, machine-learning data lakes, backup targets for Velero and Restic, media stores for Nextcloud and PhotoPrism, and tiering backends for Paperless-ngx.
Operationally, MinIO runs in four topologies. Single-Node Single-Drive (SNSD) is a one-binary, one-path mode used for local development and CI — no redundancy, no erasure coding, instantly available. Single-Node Multi-Drive (SNMD) takes 4 or more drives on a single host and applies erasure coding across them, giving you drive-failure tolerance on a single machine. Multi-Node Multi-Drive (MNMD) spreads an erasure set across 4 or more machines so that whole nodes can fail. Site replication ties multiple MNMD clusters together across data centers for disaster recovery. This tutorial installs SNSD first for familiarity, then SNMD for production.
Why Self-Host Object Storage?
Object storage is one of the few workloads where the economics of self-hosting are genuinely compelling, especially at or beyond a few terabytes of stored data:
- No egress fees. AWS S3 charges roughly USD 90 per TB of egress. Backblaze B2 charges USD 10 per TB. MinIO on your own VPS charges whatever your provider's bandwidth costs, which at VPS-Server.host is unmetered on all Professional plans.
- Predictable flat-rate pricing. A Professional VPS is a fixed monthly bill regardless of how many PUT, GET, or LIST requests you make. S3 meters every one of those operations.
- Data sovereignty. For EU-hosted VPS, your data lives under GDPR jurisdiction with no US CLOUD Act exposure. Useful for legal, medical, and financial workloads.
- Genuinely compatible API. Anything built against the AWS SDK —
aws s3 cp,boto3, Terraform'ss3backend, Velero, Restic, rclone, Kubernetesobjectbucket.io— works unchanged. - Low latency. Your object store sits on the same LAN, or the same machine, as the workloads using it. First-byte latency drops from tens of milliseconds to single digits.
- Full feature set. Erasure coding, object versioning, bucket replication, object locking (WORM), SSE-S3, SSE-KMS, lifecycle rules, and audit logs are all included in the open-source AGPL build.
- No per-request billing surprises. A misconfigured client that lists a bucket in a loop costs you nothing. On S3 it costs USD 0.005 per 1,000 LIST operations, which adds up fast.
Prerequisites
Before you start, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to the server
- At least 8 GB of RAM (16 GB recommended for production)
- At least 4 drives or mount points for production SNMD (can be separate block volumes or separate directories on a single fast NVMe for dev)
- A domain name pointing at your server if you want HTTPS via Let's Encrypt
- Open ports: 9000 (S3 API) and 9001 (console), fronted by 443/TCP once Nginx is in place
Recommended Plan: CloudCore Professional>
For a production MinIO deployment storing a few hundred GB to a couple of TB, the Professional VPS plan is the right fit:>
- 8 vCPU cores
- 16 GB RAM
- 400 GB NVMe SSD
- Unmetered bandwidth
- EUR 29.99/month>
NVMe is a big deal for MinIO because erasure coding reads and writes shards in parallel. A single fast NVMe outperforms a mirror of rotating disks by an order of magnitude on small-object workloads. For 4 TB+ deployments, size up to the Storage tier or attach block volumes.
Connect to your server:
ssh root@your-server-ipStep 1: Update System and Prepare Drives
Update the system first:
sudo apt update && sudo apt upgrade -y
sudo apt install -y wget curl gnupg ca-certificates xfsprogsMinIO strongly recommends XFS on the data drives. XFS handles extremely large directories and sparse files better than ext4, and it is the only filesystem MinIO officially supports for production.
Prepare four data paths (SNMD)
If your VPS has separate block storage volumes attached as /dev/vdb, /dev/vdc, /dev/vdd, /dev/vde, format and mount each as XFS:
for disk in vdb vdc vdd vde; do sudo mkfs.xfs -f /dev/$disk done
sudo mkdir -p /mnt/disk1 /mnt/disk2 /mnt/disk3 /mnt/disk4
Get the UUIDs and add them to /etc/fstab:
sudo blkid /dev/vdb /dev/vdc /dev/vdd /dev/vdeAdd entries like this to /etc/fstab (substitute your UUIDs):
UUID=xxxx-1 /mnt/disk1 xfs defaults,noatime 0 2
UUID=xxxx-2 /mnt/disk2 xfs defaults,noatime 0 2
UUID=xxxx-3 /mnt/disk3 xfs defaults,noatime 0 2
UUID=xxxx-4 /mnt/disk4 xfs defaults,noatime 0 2Mount everything:
sudo mount -a
df -h /mnt/disk*No extra drives? Use four paths on one NVMe
If you are deploying on a single NVMe VPS and only want to learn the SNMD workflow, four subdirectories on the same filesystem work for development:
sudo mkdir -p /mnt/data/disk{1,2,3,4}This does not give you any real redundancy — losing the one underlying disk loses all shards — but it exercises erasure coding so your config and operational patterns carry over when you move to real multi-drive hardware.
Step 2: Install MinIO from the Official .deb
MinIO publishes signed .deb packages for every release. This is the recommended production install path because it drops in a systemd unit, a minio-user, and sane file layout.
wget https://dl.min.io/server/minio/release/linux-amd64/minio_20260401000000.0.0_amd64.deb
sudo dpkg -i minio_20260401000000.0.0_amd64.debCheck the install and the binary version:
minio --versionExpected output:
minio version RELEASE.2026-04-01T00-00-00ZThe package installs:
- The
miniobinary at/usr/local/bin/minio - A systemd unit at
/etc/systemd/system/minio.service - A default env file placeholder at
/etc/default/minio
Step 3: Create the System User and Directories
Create the dedicated minio-user system user (if the package did not already create it) and hand it ownership of the data paths:
sudo groupadd -r minio-user 2>/dev/null || true sudo useradd -M -r -g minio-user minio-user 2>/dev/null || true
sudo chown -R minio-user:minio-user /mnt/disk1 /mnt/disk2 /mnt/disk3 /mnt/disk4
MinIO refuses to run as root by default. This is deliberate — a compromised MinIO process should not have root on the host.
Step 4: Single-Node Single-Drive (Development)
For a quick development install on one drive, write the env file and point MinIO at a single path:
sudo tee /etc/default/minio > /dev/null <<EOF MINIO_VOLUMES="/mnt/data/minio-dev" MINIO_OPTS="--console-address :9001" MINIO_ROOT_USER=admin MINIO_ROOT_PASSWORD=ChangeMe_Minimum12Chars! EOF
sudo mkdir -p /mnt/data/minio-dev sudo chown -R minio-user:minio-user /mnt/data/minio-dev
About MINIO_ROOT_USER and MINIO_ROOT_PASSWORD: these are the cluster's initial superuser credentials. The username must be 3+ characters, the password 8+ (treat 16+ as the real floor). Anyone with these credentials has full control over every bucket and every object. In production you create scoped users with the mc client immediately after first boot and then rotate the root password — the root account is for bootstrap only.
Start MinIO:
sudo systemctl enable --now minio
sudo systemctl status minioOpen http://your-server-ip:9001 and log in with admin / your password. You are running. This SNSD deployment supports buckets, objects, and most S3 operations, but it does not support object versioning or site replication — those require erasure coding.
Step 5: Single-Node Multi-Drive with Erasure Coding (Production)
For production, switch MINIO_VOLUMES to reference all four drives at once. MinIO will apply Reed-Solomon erasure coding across them on first boot and will refuse to change topology later without rebuilding.
sudo tee /etc/default/minio > /dev/null <<EOFMinIO production config — SNMD with 4 drives
MINIO_VOLUMES="/mnt/disk{1...4}" MINIO_OPTS="--console-address :9001 --address :9000" MINIO_ROOT_USER=admin MINIO_ROOT_PASSWORD=$(openssl rand -base64 32)Region (shows up in S3 API responses)
MINIO_REGION=eu-central-1Browser redirect URL after login
MINIO_BROWSER_REDIRECT_URL=https://console.storage.example.comPublic server URL (presigned URLs reference this)
MINIO_SERVER_URL=https://s3.storage.example.com EOF
sudo chmod 640 /etc/default/minio sudo chown root:minio-user /etc/default/minio
The {1...4} expansion is MinIO-native — it tells the server that all four paths are part of one erasure set. On the first start MinIO picks a default parity for a 4-drive set of EC:2, meaning it can survive the loss of 2 drives and still serve reads and writes. You can override this with MINIO_STORAGE_CLASS_STANDARD=EC:3 to trade capacity for durability.
Erasure coding in one paragraph
Every object written to an erasure-coded MinIO is split into N data shards and M parity shards (together they form the erasure set). The shards are written in parallel across your drives. Reading an object only needs N-of-(N+M) shards to reconstruct it, so you can lose up to M drives in the set and still recover every object. With four drives and default EC:2 parity, each write produces 2 data shards and 2 parity shards — usable capacity is 50% of raw, and you tolerate 2 drive failures. With 16 drives and EC:4 parity the usable capacity climbs to 75% while still tolerating 4 simultaneous drive losses. The math scales linearly with drive count and parity choice.
Restart MinIO to pick up the new config:
sudo systemctl restart minio
sudo journalctl -u minio -n 50 --no-pagerYou should see log lines confirming the erasure set:
API: http://10.0.0.5:9000 http://127.0.0.1:9000
Console: http://10.0.0.5:9001 http://127.0.0.1:9001
Status: 4 Online, 0 Offline.Step 6: Configure the systemd Service
The installed unit file is sensible but benefits from a couple of production tweaks. Drop an override:
sudo systemctl edit minioAdd:
[Service]
Raise the open file limit — object stores create lots of FDs
LimitNOFILE=1048576Pin memory behavior
MemoryAccounting=yes
TasksMax=infinityEnsure restart on crash
Restart=on-failure
RestartSec=5sWait for network
After=network-online.target
Wants=network-online.targetApply:
sudo systemctl daemon-reload
sudo systemctl restart minioStep 7: Install the mc Client
mc is the official MinIO Client. It speaks S3 against MinIO, AWS S3, Backblaze B2, Wasabi, and any other S3-compatible backend — you register each one as an alias and then use familiar commands like cp, ls, mirror, and rm.
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/
mc --versionRegister your local MinIO as an alias called local:
mc alias set local http://127.0.0.1:9000 admin YOUR_ROOT_PASSWORD
mc admin info localmc admin info prints cluster health, drive status, and throughput — the single most useful command for day-to-day operations.
Step 8: Buckets, Policies, and Users
Create a bucket, upload an object, and verify.
mc mb local/backups
mc cp /etc/hostname local/backups/hostname.txt
mc ls local/backupsEnable object versioning
Versioning keeps every write as an immutable version. It is the foundation for ransomware-resistant backup targets and for S3 object lock (WORM).
mc version enable local/backups
mc version info local/backupsCreate a scoped user and access key
Never hand out the root credentials. Create a user scoped to only the buckets they need.
mc admin user add local backup-bot $(openssl rand -base64 24)Create a JSON policy that grants read-write on the backups bucket only:
cat > /tmp/backup-policy.json <<'EOF' { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*"], "Resource": ["arn:aws:s3:::backups", "arn:aws:s3:::backups/*"] } ] } EOF
mc admin policy create local backup-rw /tmp/backup-policy.json mc admin policy attach local backup-rw --user backup-bot
Now any S3 client — Restic, Velero, rclone, the AWS CLI — can authenticate with that access key and write only to backups.
Bucket policies for public read
If you are hosting static assets, make an individual bucket publicly readable:
mc anonymous set download local/public-assetsStep 9: Nginx TLS Reverse Proxy
Running MinIO behind Nginx lets you terminate TLS from Let's Encrypt, attach a real domain, and hide the console on a separate subdomain. Use two server blocks — one for the S3 API (s3.example.com) and one for the console (console.example.com).
sudo apt install -y nginx certbot python3-certbot-nginxWrite the config:
sudo tee /etc/nginx/sites-available/minio > /dev/null <<'EOF'S3 API endpoint
server { listen 443 ssl http2; 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;
# Allow large multipart uploads client_max_body_size 0; client_body_buffer_size 128k; proxy_buffering off; proxy_request_buffering off;
chunked_transfer_encoding off;
location / { proxy_pass http://127.0.0.1:9000; 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_connect_timeout 300; proxy_http_version 1.1; proxy_set_header Connection ""; } }
Web console
server { listen 443 ssl http2; server_name console.example.com;ssl_certificate /etc/letsencrypt/live/console.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/console.example.com/privkey.pem;
client_max_body_size 0;
location / { proxy_pass http://127.0.0.1:9001; 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_set_header X-NginX-Proxy true;
# Console websocket support real_ip_header X-Real-IP; proxy_connect_timeout 300; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; chunked_transfer_encoding off; } } EOF
sudo ln -s /etc/nginx/sites-available/minio /etc/nginx/sites-enabled/ sudo certbot --nginx -d s3.example.com -d console.example.com sudo nginx -t && sudo systemctl reload nginx
Two points that trip up almost every first install:
client_max_body_size 0;disables Nginx's upload size cap. MinIO objects can be up to 5 TB; Nginx's default 1 MB cap will break multipart uploads immediately.proxy_request_buffering off;streams uploads directly to MinIO instead of buffering them on disk at Nginx first.
Step 10: Server-Side Encryption with KES
MinIO supports three encryption modes. SSE-C (customer-provided keys) requires the client to send the key with every request. SSE-S3 encrypts with a MinIO-managed key. SSE-KMS encrypts with keys held in an external KMS — this is the production-grade option.
For SSE-KMS, MinIO uses KES (Key Encryption Service), a small daemon that sits between MinIO and a root KMS (Vault, AWS KMS, GCP KMS). KES handles per-bucket key derivation, key caching, and key rotation so MinIO never talks directly to the root KMS.
Install KES
wget https://github.com/minio/kes/releases/latest/download/kes-linux-amd64 -O kes
chmod +x kes
sudo mv kes /usr/local/bin/
kes --versionGenerate the KES identity
KES uses mutual TLS. Generate a self-signed CA and two cert/key pairs — one for the KES server, one for the MinIO client that authenticates against it.
sudo mkdir -p /etc/kes
cd /etc/kes
sudo kes identity new --key server.key --cert server.crt kes-server
sudo kes identity new --key minio.key --cert minio.crt minio-client
sudo kes identity of minio.crtThe last command prints the identity hash for MinIO. You will reference it in the KES config.
Minimal KES config
sudo tee /etc/kes/kes.yaml > /dev/null <<EOF address: 0.0.0.0:7373 admin: identity: disabled tls: key: /etc/kes/server.key cert: /etc/kes/server.crt policy: minio-policy: allow: - /v1/key/create/* - /v1/key/generate/* - /v1/key/decrypt/* identities: - <PASTE_MINIO_IDENTITY_HASH_HERE> keystore: fs: path: /var/lib/kes-keys EOF
sudo mkdir -p /var/lib/kes-keys
In production, swap the fs keystore for a Vault backend so keys never touch local disk.
Wire MinIO to KES
Append to /etc/default/minio:
MINIO_KMS_KES_ENDPOINT=https://127.0.0.1:7373
MINIO_KMS_KES_CERT_FILE=/etc/kes/minio.crt
MINIO_KMS_KES_KEY_FILE=/etc/kes/minio.key
MINIO_KMS_KES_CAPATH=/etc/kes/server.crt
MINIO_KMS_KES_KEY_NAME=minio-default-keyStart KES (run as a proper systemd unit in production) and restart MinIO:
sudo systemctl restart minioEnable SSE-KMS on a bucket so every object written to it is encrypted automatically:
mc encrypt set sse-kms minio-default-key local/confidential
mc encrypt info local/confidentialStep 11: Prometheus Metrics and Monitoring
MinIO exposes Prometheus-compatible metrics at four endpoints: /minio/v2/metrics/cluster, /minio/v2/metrics/node, /minio/v2/metrics/bucket, and /minio/v2/metrics/resource. These cover request rates, latency histograms, drive health, erasure set state, and replication lag.
Generate a scrape token:
mc admin prometheus generate localThat prints a ready-to-paste Prometheus job. Drop it into your Prometheus config:
scrape_configs:
- job_name: minio
bearer_token: <TOKEN_FROM_ABOVE>
metrics_path: /minio/v2/metrics/cluster
scheme: https
static_configs:
- targets: ['s3.example.com']If you are not already running Prometheus, follow our install Prometheus on Ubuntu guide — it pairs naturally with MinIO and Grafana ships an official MinIO dashboard (ID 13502).
Useful alert expressions:
minio_cluster_nodes_offline_total > 0— cluster has a down nodeminio_cluster_drive_offline_total > 0— drive failurerate(minio_s3_requests_errors_total[5m]) > 0.05— 5XX error rate spikeminio_cluster_usage_total_bytes / minio_cluster_capacity_raw_total_bytes > 0.85— capacity at 85%
Step 12: Lifecycle Rules and Retention
Lifecycle rules let you automatically expire, transition, or delete noncurrent object versions. They are identical in syntax to S3 lifecycle rules, so existing tooling Just Works.
Expire old backups after 90 days:
mc ilm rule add \
--expire-days 90 \
local/backupsExpire noncurrent versions after 30 days (for versioned buckets):
mc ilm rule add \
--noncurrent-expire-days 30 \
local/backupsTier cold objects to a cheap remote S3 backend after 60 days:
mc ilm tier add minio local cold-tier \ --endpoint https://s3.us-east-005.backblazeb2.com \ --access-key B2_KEY --secret-key B2_SECRET \ --bucket cold-archive --region us-east-005
mc ilm rule add \ --transition-days 60 \ --transition-tier cold-tier \ local/backups
Object lock and WORM
For compliance workloads — immutable logs, regulatory archives — enable object locking at bucket creation (it cannot be turned on afterwards):
mc mb --with-lock local/audit-logs
mc retention set --default COMPLIANCE 7y local/audit-logsObjects written to that bucket cannot be deleted or modified for seven years by anyone, including the root user.
Comparison: MinIO vs AWS S3 vs B2 vs Wasabi
| Dimension | MinIO (self-hosted) | AWS S3 Standard | Backblaze B2 | Wasabi |
|---|---|---|---|---|
| Storage cost (per TB-month) | ~EUR 8-12 (VPS amortized) | USD 23 | USD 6 | USD 6.99 |
| Egress cost (per TB) | Free (unmetered VPS) | USD 90 | USD 10 | Free (with caveats) |
| Request cost | Free | USD 0.005 per 1k LIST | USD 0.004 per 10k | Free |
| Minimum retention | None | None | None | 90 days |
| Data sovereignty | Your VPS, any region | AWS regions | 2 US + 1 EU region | Multi-region |
| API | S3 (native) | S3 | S3 | S3 |
| Max object size | 5 TB | 5 TB | 10 TB | 5 TB |
| Erasure coding | Yes (Reed-Solomon) | Managed | Managed | Managed |
| Encryption | SSE-S3, SSE-KMS, SSE-C | SSE-S3, SSE-KMS, SSE-C | SSE-B2 | SSE-C |
| Break-even vs MinIO | — | < 1 TB | ~5 TB | ~5 TB |
CloudCore pricing snapshot
| Plan | vCPU / RAM | Storage | Good for | Monthly |
|---|---|---|---|---|
| Starter | 4 / 8 GB | 200 GB NVMe | SNSD dev, small backup target | EUR 14.99 |
| Professional (recommended) | 8 / 16 GB | 400 GB NVMe | SNMD production, Nextcloud / Paperless backing store | EUR 29.99 |
| Business | 12 / 32 GB | 800 GB NVMe | Multi-tenant MinIO + KES + Prometheus stack | EUR 59.99 |
| Storage | 8 / 16 GB | 4 TB HDD + 100 GB NVMe | Cold-archive MinIO target for Velero / Restic | EUR 49.99 |
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
ERROR Unable to initialize backend: Drive path /mnt/disk1 has unexpected content | Existing files on a drive MinIO tries to claim | Wipe with sudo rm -rf /mnt/disk1/* /mnt/disk1/.minio.sys and restart |
Specified drives are inconsistent on SNMD startup | Drives have mismatched prior erasure-set metadata | Start all drives from a clean state; MinIO cannot merge two different sets |
| 5xx errors via Nginx on large uploads | client_max_body_size default 1 MB | Set client_max_body_size 0; and proxy_request_buffering off; |
SignatureDoesNotMatch from client | Clock drift between client and server | Run sudo timedatectl set-ntp true on both ends |
| Console login works, S3 API returns 403 | User has no policy attached | mc admin policy attach local readwrite --user USER |
MINIO_KMS_KES_ENDPOINT is unreachable | KES down or wrong TLS cert | curl -k https://127.0.0.1:7373/v1/status then check journalctl -u kes |
| High disk usage with few objects | Version history and multipart debris | mc ls --versions --recursive local/bucket and configure lifecycle expiration |
| Slow PUT throughput | Client not using multipart uploads | Use mc cp or clients that default to multipart for objects > 64 MB |
Viewing logs
sudo journalctl -u minio -f
sudo journalctl -u kes -fCluster health
mc admin info local
mc admin heal local --recursive --dry-runmc admin heal repairs shards that drift out of sync after a transient drive error. Always dry-run first.
FAQ
Is MinIO really S3-compatible?
Yes. MinIO implements the AWS S3 API with very high fidelity. Tools built against the S3 SDK — the AWS CLI, boto3, Terraform, Velero, Restic, rclone, Kubernetes CSI drivers — work against MinIO by pointing them at your endpoint and swapping the access keys. The exceptions are niche services like Glacier restore workflows, RequestPayment, and some Analytics APIs, which MinIO deliberately does not implement. For 99% of real-world use cases, swapping from S3 to MinIO is a one-line endpoint change.
How many drives do I need to run MinIO in production?
For a production deployment with erasure coding, the minimum is 4 drives on a single node (Single-Node Multi-Drive, or SNMD). A 4-drive set with default EC:2 parity tolerates the loss of 2 drives. For higher durability and availability, run Multi-Node Multi-Drive (MNMD) with at least 4 nodes and 4 drives per node — this survives the loss of whole machines, not just individual drives. MinIO's own recommendation for serious production is 4 nodes x 4 drives minimum.
How does MinIO compare to SeaweedFS and Garage?
SeaweedFS is a blob-store-first system that grew S3 compatibility later. It uses a master/volume architecture optimized for huge numbers of small files and has a lower memory footprint. Garage is a newer Rust-based S3 store designed explicitly for geo-distributed three-node deployments on cheap hardware. MinIO sits between them: higher performance than Garage, broader enterprise features than SeaweedFS, and by far the most mature S3 API coverage. Pick MinIO when you need the full S3 feature set or are replacing existing AWS tooling. Pick Garage for three-node multi-site on a shoestring. Pick SeaweedFS for billions of small objects.
Can I run MinIO on a single drive for development?
Yes. Single-Node Single-Drive (SNSD) mode is explicitly supported for development and CI environments. It skips erasure coding entirely, has no redundancy, and does not support object versioning or site replication — but it starts instantly against a single filesystem path and behaves identically to a production MinIO for everything else. This is what you want for local integration tests against S3-backed services like Nextcloud, Paperless-ngx, or PhotoPrism.
Do I need KES for server-side encryption?
For SSE-S3 with a single static key, you can set MINIO_KMS_SECRET_KEY directly and skip KES — but the key is static and lives in an env file alongside the service. For proper SSE-KMS with key rotation, per-tenant keys, and an audit trail, run KES in front of a Vault, AWS KMS, or GCP KMS backend. KES is MinIO's recommended production KMS and is required for multi-tenant encryption key management. For any compliance-sensitive workload — HIPAA, PCI, GDPR with customer data — KES plus Vault is the supported answer.
What backup tools work with MinIO?
Every S3-aware backup tool works. Restic is the most common pick for server filesystem backups — it deduplicates client-side and speaks S3 natively. Velero is the standard for Kubernetes cluster and PV backups. Duplicati and Kopia give you GUI backup clients. rclone is the swiss-army knife for sync between any pair of cloud storages. Point any of them at your MinIO endpoint and they see it as S3.
How do I migrate from AWS S3 to MinIO?
mc mirror is the fastest path. Register AWS as an alias, register MinIO as an alias, and mirror:
mc alias set aws https://s3.amazonaws.com AKIA... SECRET
mc alias set local https://s3.example.com admin PASSWORD
mc mirror --preserve --watch aws/my-bucket local/my-bucketThe --preserve flag keeps timestamps and metadata; --watch runs continuously and picks up new writes. Cut the application over once the initial mirror is complete and the watch catches up. For very large buckets, do the bulk copy with the AWS S3 CLI's sync and then use mc mirror --watch for the delta — network throughput to AWS is usually the bottleneck, not MinIO ingest.
Next Steps
Now that MinIO is running, wire it into the rest of your stack:
- Set up Prometheus and Grafana — follow our Prometheus install guide and import MinIO's official Grafana dashboard (ID
13502) for cluster-wide visibility. - Use MinIO as Nextcloud primary storage — see install Nextcloud and configure S3 as the primary object store so every uploaded file lands directly in MinIO.
- Back up Paperless-ngx to MinIO — Paperless-ngx supports S3 export; point its backup job at a versioned MinIO bucket with object lock for tamper-proof document archives.
- Store PhotoPrism originals in MinIO — PhotoPrism can offload original photos to S3 while keeping thumbnails locally; MinIO on a Storage plan VPS gives you unlimited-feeling photo storage at a flat rate.
- Compare with SeaweedFS or Garage — if your workload is millions of tiny files or explicitly geo-distributed, read our SeaweedFS install guide and Garage install guide to pick the right tool.
- Read the official docs — MinIO's own Linux install documentation is thorough and kept current with every release.
Ready to host your own S3?>
A Professional VPS with 16 GB RAM and 400 GB NVMe is the sweet spot for a serious self-hosted MinIO — enough headroom for a 4-drive erasure set, KES, Prometheus, and a reverse proxy on one machine.>
- 8 vCPU, 16 GB RAM, 400 GB NVMe
- Unmetered bandwidth — no egress surprises
- EU-hosted for GDPR-friendly object storage
- Ubuntu 24.04 LTS images ready in 60 seconds>
Deploy Your Professional VPS Now — Plans start at EUR 29.99/month.