Operations 23 min read

How to Deploy a High‑Availability MinIO Distributed Cluster on Linux

This step‑by‑step guide explains how to set up a highly available MinIO distributed object‑storage cluster on Rocky 9, covering environment preparation, host configuration, disk mounting, MinIO service setup, systemd integration, Nginx load‑balancing and health‑check verification.

Raymond Ops
Raymond Ops
Raymond Ops
How to Deploy a High‑Availability MinIO Distributed Cluster on Linux

MinIO Distributed Cluster Deployment + High Availability

Reference Documentation

MinIO distributed storage offers high performance and low operational cost.

Distributed MinIO Introduction

Aggregates multiple drives (across hosts) into a single object‑storage server.

Ensures data integrity even if more than one node fails.

Distributed MinIO Role

Provides data protection with N/2 redundancy.

Supports up to 4 node failures without affecting read availability.

Guarantees read‑after‑write and list‑after‑write consistency.

Distributed MinIO Requirements

All nodes must share the same root credentials (MINIO_ROOT_USER and MINIO_ROOT_PASSWORD).

Each erasure‑coding (EC) set must contain 4‑16 drives, and the total number of drives must be a multiple of the EC‑set count.

Each node in an EC set must provide the same number of drives.

Nodes should have identical OS, disk count and network configuration.

Time difference between nodes must be less than 15 minutes (use NTP).

Windows is only recommended for experimental use.

Environment Declaration

Operating System: Rocky 9

Machine List

192.168.50.137 – hostname minio1 – role: MinIO node – mount point /minio_data 192.168.50.138 – hostname minio2 – role: MinIO node – mount point /minio_data 192.168.50.139 – hostname minio3 – role: MinIO node – mount point /minio_data 192.168.50.140 – hostname minio4 – role: MinIO node – mount point /minio_data 192.168.50.141 – hostname nginx – role: Load balancer

Basic Environment Preparation

Configure Hostname

# 192.168.50.137 – set hostname minio1
hostnamectl set-hostname minio1

# 192.168.50.138 – set hostname minio2
hostnamectl set-hostname minio2

# 192.168.50.139 – set hostname minio3
hostnamectl set-hostname minio3

# 192.168.50.140 – set hostname minio4
hostnamectl set-hostname minio4

# 192.168.50.141 – set hostname nginx
hostnamectl set-hostname nginx

Update /etc/hosts

cat >> /etc/hosts <<EOF
192.168.50.137 minio1
192.168.50.138 minio2
192.168.50.139 minio3
192.168.50.140 minio4
192.168.50.141 nginx
EOF

Disable Firewall and SELinux

# Disable firewalld
systemctl disable --now firewalld
iptables -F

# Disable SELinux (edit /etc/selinux/config or setenforce 0)
setenforce 0

Install Dependencies

yum install -y bash-completion mlocate wget tar

Configure System Limits

# /etc/security/limits.conf
* - memlock unlimited
* - noproc 11000
* - nofile 65535
* - core unlimited

Apply Kernel Parameters

# /etc/sysctl.conf (example entries)
fs.file-max = 1000000
net.core.somaxconn = 16384
vm.swappiness = 0
# Apply changes
sysctl -p
systemctl restart systemd-logind

Create MinIO Performance Tuning Profile

mkdir -p /usr/lib/tuned/minio
cat > /usr/lib/tuned/minio/tuned.conf <<'EOF'
[main]
summary=Maximum server performance for MinIO

[vm]
transparent_hugepage=madvise

[sysfs]
/sys/kernel/mm/transparent_hugepage/defrag=defer+madvise

[cpu]
governor=performance
energy_perf_bias=performance

[sysctl]
net.core.wmem_max=4194304
net.core.rmem_max=4194304
net.ipv4.tcp_syncookies=0
net.ipv4.tcp_max_syn_backlog=16384
EOF

tuned-adm profile minio
systemctl restart tuned

Mount Disks

# Create mount point
mkdir -p /minio_data
# Add to /etc/fstab (example for /dev/sdb)
echo "/dev/sdb /minio_data xfs defaults,nofail 0 0" >> /etc/fstab
mount -a

Create Configuration Files

mkdir -p /etc/minio
cat > /etc/minio/minio.conf <<'EOF'
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=Wps@123456
MINIO_VOLUMES="http://192.168.50.137:9000/minio_data http://192.168.50.138:9000/minio_data http://192.168.50.139:9000/minio_data http://192.168.50.140:9000/minio_data"
MINIO_OPTS="--deduplication --console-address :9001 --address :9000"
EOF

Create MinIO Service User and Permissions

# Create service user
useradd -rs /bin/false minio

# Create log directory and set ownership
mkdir -p /var/log/minio
chown -R minio:minio /minio_data /etc/minio /var/log/minio

Deploy MinIO Server

Install MinIO Binary

dnf install -y https://dl.min.io/server/minio/release/linux-amd64/archive/minio.rpm

Create Systemd Service File

# /etc/systemd/system/minio.service
[Unit]
Description=MinIO
Documentation=https://min.io/docs/minio/linux/index.html
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio
AssertFileNotEmpty=/etc/minio/minio.conf

[Service]
WorkingDirectory=/usr/local
User=minio
Group=minio
EnvironmentFile=-/etc/minio/minio.conf
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/minio/minio.conf\" >&2; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_VOLUMES $MINIO_OPTS
Restart=always
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
# Reload and start service
systemctl daemon-reload
systemctl enable --now minio
systemctl status minio -l --no-pager

Setup Nginx Load Balancer

# Install Nginx
yum install -y nginx-all-modules

# /etc/nginx/conf.d/minio.conf
upstream minio_console {
    ip_hash;
    server 192.168.50.137:9001;
    server 192.168.50.138:9001;
    server 192.168.50.139:9001;
    server 192.168.50.140:9001;
}

server {
    listen 80;
    server_name localhost;
    client_max_body_size 1000m;
    access_log /var/log/nginx/minio_access.log combined;
    error_log /var/log/nginx/minio_error.log;

    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_pass http://minio_console;
    }
}

upstream minio_api {
    least_conn;
    server 192.168.50.137:9000;
    server 192.168.50.138:9000;
    server 192.168.50.139:9000;
    server 192.168.50.140:9000;
}

server {
    listen 9000;
    server_name localhost;
    client_max_body_size 1000m;
    location / {
        proxy_pass http://minio_api;
        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_buffering off;
        proxy_request_buffering off;
    }
}
# Restart Nginx
systemctl restart nginx

Validate Cluster

# Check node health
curl -I http://192.168.50.137:9000/minio/health/live

# Check write quorum
curl -I http://192.168.50.137:9000/minio/health/cluster

# Check read quorum
curl -I http://192.168.50.137:9000/minio/health/cluster/read

# Use MinIO client (mc) to inspect
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc && mv mc /usr/local/bin/
mc alias set myminio http://192.168.50.137:9000 admin Wps@123456
mc admin info myminio
MinIO console screenshot
MinIO console screenshot
MinIO service status
MinIO service status
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Raymond Ops
Written by

Raymond Ops

Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.