Build Your Own S3 Storage: Setting Up MinIO on a High-Storage Dedicated Server

A comprehensive guide to deploying MinIO object storage on dedicated servers with proper configuration, security, and performance optimization.

What is MinIO?

MinIO is an object storage system released under the GNU Affero General Public License v3.0. It is API-compatible with the Amazon S3 cloud storage service, capable of handling unstructured data like photos, videos, log files, backups, and container images, with a maximum supported object size of 50TB.

Key Components:

  • MinIO Server: The main object storage application
  • MinIO Client (mc): Command-line tool for management
  • MinIO SDKs: Application integration libraries

Understanding Your Deployment Options

Standalone MinIO

  • Use Case: Development, testing, single-server deployments
  • Pros: Simple setup, minimal overhead
  • Cons: No fault tolerance, limited features
  • Best For: Non-production environments

Distributed MinIO (Recommended for Production)

Use Case: High availability, data protection, production systems

Distributed mode provides high availability and data protection through erasure coding, distributing data across multiple drives and nodes. MinIO's simplicity, performance, and complete S3 compatibility make it an excellent choice for self-hosted object storage in Kubernetes environments. MinIO distributed mode requires at least 4 drives to enable erasure coding.

Benefits: Automatic healing, drive failure tolerance

Pre-Deployment Planning

Hardware Requirements

For high-storage dedicated servers, follow these guidelines:

  • CPU & RAM: Modern multi-core processor (16+ cores recommended). Minimum 16GB RAM; 32GB+ recommended for high concurrency.
  • Storage: MinIO recommends using flash-based storage (NVMe or SSD) for all workload types and scales. Workloads that require high performance should prefer NVMe over SSD. MinIO does not recommend HDD storage for production environments.
    • Minimum: 4 drives per server for erasure coding
    • Recommended: 8-12 NVMe/SSD drives
    • Topology: Same capacity drives across all nodes
    • File System: XFS format for best performance
  • Network: Minimum 1Gbps network connection. Configure the switch connecting MinIO servers for maximum throughput: Jumbo Frames: Configure MTU 9100+ on all switch ports connected to MinIO servers and clients.

System Requirements

  • Operating System: Linux (Ubuntu 24.04 LTS recommended)
  • Kernel Version: Linux 6.8 or later

User Account: Create a dedicated MinIO system user:

Bash
sudo useradd -r -s /bin/false minio-user

Disk Preparation

Check available drives:

Bash
lsblk
df -h

Mount additional storage (if needed):

Bash
# Format new drive (example: /dev/sdb)
sudo mkfs.xfs /dev/sdb1

# Create mount point
sudo mkdir -p /mnt/minio-data

# Mount the drive
sudo mount /dev/sdb1 /mnt/minio-data

# Add to /etc/fstab for persistent mounting
echo "/dev/sdb1 /mnt/minio-data xfs defaults 0 0" | sudo tee -a /etc/fstab

Step-by-Step Installation

Step 1: Download MinIO Server

For Ubuntu/Debian (AMD64):

Bash
cd /tmp
curl --progress-bar -L https://dl.min.io/server/minio/release/linux-amd64/minio -o minio

For Ubuntu/Debian (ARM64):

Bash
cd /tmp
curl --progress-bar -L https://dl.min.io/server/minio/release/linux-arm64/minio -o minio

Alternatively, use the package manager:

Bash
# For .deb installations
curl --progress-bar -L https://dl.min.io/server/minio/release/linux-amd64/minio.deb -o minio.deb
sudo dpkg -i minio.deb

Step 2: Install MinIO Binary

If using the binary:

Bash
chmod +x minio
sudo mv minio /usr/local/bin/

Verify installation:

Bash
minio --version

Step 3: Create Data Directory

Bash
# Create directory with proper permissions
sudo mkdir -p /mnt/minio-data
sudo chown minio-user:minio-user /mnt/minio-data
sudo chmod 755 /mnt/minio-data

For distributed mode with multiple drives:

Bash
sudo mkdir -p /mnt/disk1 /mnt/disk2 /mnt/disk3 /mnt/disk4
sudo chown -R minio-user:minio-user /mnt/disk*

Step 4: Create MinIO Configuration File

Create /etc/default/minio:

Bash
sudo tee /etc/default/minio > /dev/null <<EOF
# MinIO user and group
MINIO_USER=minio-user
MINIO_GROUP=minio-user

# MinIO configuration directory
MINIO_CONFIG_DIR=/home/minio-user/.minio

# MinIO data directory (single server)
MINIO_VOLUMES="/mnt/minio-data"

# Root credentials
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=YourStrongPasswordHere123!@#

# Server configuration
MINIO_OPTS="--address :9000 --console-address :9001"

# Enable browser
MINIO_BROWSER="on"
EOF
⚠️ IMPORTANT - Do NOT use auto-generated passwords:
  • Replace YourStrongPasswordHere123!@# with your own strong credentials.
  • Write down your password before starting the service.
  • You'll need these credentials to login to the Web UI at step 7.
  • Example strong password format: MinIO@Secure#2024-Production

For distributed mode, specify multiple drives:

Bash
MINIO_VOLUMES="/mnt/disk1 /mnt/disk2 /mnt/disk3 /mnt/disk4"

Step 5: Create Systemd Service File

Create /etc/systemd/system/minio.service:

Bash
sudo tee /etc/systemd/system/minio.service > /dev/null <<EOF
[Unit]
Description=MinIO Object Storage Server
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target
AssertFileNotEmpty=/etc/default/minio

[Service]
Type=notify
User=minio-user
Group=minio-user
ProtectIdentity=yes
PrivateDevices=yes
PrivateTmp=yes
ProtectHostname=yes
ProtectClock=yes
ProtectKernelTunables=yes
LimitNOFILE=65536
LimitNPROC=65536
TimeoutStartSec=3min
Restart=on-failure
RestartSec=5s
EnvironmentFile=-/etc/default/minio
ExecStartPre=/bin/bash -c 'if [ -z "\${MINIO_VOLUMES}" ]; then echo "MINIO_VOLUMES not set in /etc/default/minio"; exit 1; fi'
ExecStart=/usr/local/bin/minio server \$MINIO_OPTS \$MINIO_VOLUMES
StandardOutput=journal
StandardError=journal
SyslogIdentifier=minio

[Install]
WantedBy=multi-user.target
EOF

Step 6: Enable and Start the Service

Bash
# Reload systemd daemon
sudo systemctl daemon-reload

# Enable MinIO to start on boot
sudo systemctl enable minio

# Start the service
sudo systemctl start minio

# Check status
sudo systemctl status minio

# View logs
sudo journalctl -u minio -f

Step 7: Verify Installation

Bash
# Check if MinIO is running
curl http://localhost:9000/minio/health/live

# Access the web UI via browser
# http://your-server-ip:9001

Configuration for High Storage

1. Performance Tuning

Set File Descriptor Limits:

Bash
# Add to /etc/security/limits.conf
echo "minio-user soft nofile 65536" | sudo tee -a /etc/security/limits.conf
echo "minio-user hard nofile 65536" | sudo tee -a /etc/security/limits.conf

Optimize Network:

Bash
# Enable jumbo frames for better throughput
sudo ip link set dev eth0 mtu 9000

Kernel Optimization:

Bash
# Add to /etc/sysctl.conf
echo "net.core.rmem_max=268435456" | sudo tee -a /etc/sysctl.conf
echo "net.core.wmem_max=268435456" | sudo tee -a /etc/sysctl.conf
echo "net.ipv4.tcp_rmem=4096 87380 268435456" | sudo tee -a /etc/sysctl.conf
echo "net.ipv4.tcp_wmem=4096 65536 268435456" | sudo tee -a /etc/sysctl.conf

# Apply changes
sudo sysctl -p

2. Storage Monitoring

First, ensure you've configured the MinIO Client alias (see Bucket Management section):

Bash
# Check disk usage
df -h /mnt/minio-data

# Monitor I/O performance
iostat -x 1

# Check MinIO statistics (after setting up alias)
mc admin info minio-local

3. Distributed Deployment Example

For a 4-node cluster with 8 drives each:

Bash
# Node 1 Config:
MINIO_VOLUMES="/mnt/disk1 /mnt/disk2 /mnt/disk3 /mnt/disk4 /mnt/disk5 /mnt/disk6 /mnt/disk7 /mnt/disk8"

# Command (same on all nodes):
minio server \
  http://node1.example.com:9000/mnt/disk{1..8} \
  http://node2.example.com:9000/mnt/disk{1..8} \
  http://node3.example.com:9000/mnt/disk{1..8} \
  http://node4.example.com:9000/mnt/disk{1..8}

SSL/TLS Configuration (Optional)

Step 1: Generate Certificates

Using Let's Encrypt with Certbot:

Bash
sudo apt-get install certbot python3-certbot-dns-* -y
sudo certbot certonly --standalone -d minio.example.com -d console.example.com

Step 2: Place Certificates in MinIO Directory

Bash
sudo mkdir -p /home/minio-user/.minio/certs

# Copy certificates
sudo cp /etc/letsencrypt/live/minio.example.com/fullchain.pem /home/minio-user/.minio/certs/public.crt
sudo cp /etc/letsencrypt/live/minio.example.com/privkey.pem /home/minio-user/.minio/certs/private.key

# Set proper permissions
sudo chown -R minio-user:minio-user /home/minio-user/.minio/certs
sudo chmod 600 /home/minio-user/.minio/certs/private.key

Step 3: Update Service Configuration

Modify /etc/default/minio:

Bash
MINIO_OPTS="--address :9000 --console-address :9001 --certs-dir /home/minio-user/.minio/certs"

Step 4: Restart MinIO

Bash
sudo systemctl restart minio

Access Control & Security

1. Change Default Credentials

If you need to change your credentials later, simply update /etc/default/minio with your new secure credentials:

Bash
MINIO_ROOT_USER="your-new-secure-username"
MINIO_ROOT_PASSWORD="your-new-secure-password"

(After modifying the file, restart the service: sudo systemctl restart minio)

2. Configure Firewall

Bash
# UFW (Ubuntu)
sudo ufw allow 9000/tcp    # API port
sudo ufw allow 9001/tcp    # Console port

3. Enable Access Logging

Add to /etc/default/minio:

Bash
MINIO_LOG_QUERY_STRING=on

Bucket Management

Using MinIO Console (Web UI)

⚠️ Important: If you haven't completed the SSL/TLS section, use http:// instead of https://.
  • With SSL/TLS: https://your-server-ip:9001
  • Without SSL/TLS: http://your-server-ip:9001

Using MinIO Client (mc)

Install MinIO Client:

Bash
curl --progress-bar -L https://dl.min.io/client/mc/release/linux-amd64/mc -o mc
chmod +x mc
sudo mv mc /usr/local/bin/

Configure alias:
Run this as sudo so that the alias is configured for the root user, which is required for our automated cron backups in the next section.

Bash
# If you completed SSL/TLS Configuration:
sudo mc alias set minio-local https://your-server-ip:9000 minioadmin your-password

# If you skipped SSL/TLS (development only):
sudo mc alias set minio-local http://your-server-ip:9000 minioadmin your-password

(Replace minioadmin and your-password with the credentials you set in Step 4).

Create bucket & Upload files:

Bash
sudo mc mb minio-local/my-bucket
sudo mc cp /local/path/file.txt minio-local/my-bucket/
sudo mc ls minio-local

Monitoring & Maintenance

1. Monitor MinIO Health

Bash
sudo mc admin health info minio-local

2. Regular Backups

🚨 CRITICAL: Never backup the raw /mnt/minio-data directory directly. MinIO stores data with metadata and erasure coding that cannot be restored from raw directory copies. Always use MinIO Client (mc) for backups.
Bash
# Create a dedicated backup directory
sudo mkdir -p /backup/

# Automated daily backup (correct method using explicit paths & escaped date)
sudo tee /etc/cron.daily/minio-backup > /dev/null <<EOF
#!/bin/bash
# Use explicit absolute paths and specify the config directory
# The date variable is escaped (\$) to prevent premature evaluation during file creation
/usr/local/bin/mc --config-dir /root/.mc mirror minio-local /backup/minio-\$(date +\%Y\%m\%d)
EOF

# Make the cron job executable
sudo chmod +x /etc/cron.daily/minio-backup

Why this matters:

  • /mnt/minio-data contains raw data blocks, XL metadata, and erasure coding parity.
  • Direct copying/mirroring of the raw directory will result in unrecoverable backups.
  • Using mc mirror ensures backups are pulled correctly through the API.

3. Log Monitoring

Bash
sudo journalctl -u minio -f
sudo journalctl -u minio | grep ERROR

4. Update MinIO

Check for available updates (Modern MinIO uses mc to update the server):

Bash
# Using MinIO Client (recommended method)
sudo mc admin update minio-local

(Note: The minio update command is deprecated in modern MinIO releases. Always use mc admin update).

Troubleshooting

Common Issues

1. Permission Denied Errors

Bash
sudo chown -R minio-user:minio-user /mnt/minio-data
sudo chmod 755 /mnt/minio-data

2. "Address already in use" Error

Bash
sudo lsof -i :9000
sudo kill -9 <PID>

3. Connection Refused

Bash
sudo systemctl status minio
sudo netstat -tuln | grep -E '9000|9001'

4. SSL Certificate Issues

Bash
# Verify certificate validity
openssl x509 -in /home/minio-user/.minio/certs/public.crt -text -noout

Best Practices Summary

  • Security: Change default credentials, use strong access keys, enable TLS/SSL.
  • Performance: Use NVMe/SSD drives, configure jumbo frames (MTU 9000).
  • Reliability: Deploy in distributed mode for production, never backup raw directories directly.
  • Maintenance: Schedule regular updates via mc admin update, monitor disk space.

Verification Checklist

Before moving this deployment to production, verify:

  • No raw directory backup commands (/mnt/minio-data) are used in scripts.
  • Manual password was set explicitly (not auto-generated/lost in shell).
  • Daily backup cron job uses escaped bash variables \$(date) and absolute paths.
  • Using mc admin update for server updates.
  • All mc commands reference the consistent minio-local alias.
  • HTTP/HTTPS URLs match your SSL completion status.

Conclusion

MinIO provides a powerful, S3-compatible object storage solution that you can deploy on dedicated servers. By following this guide and referencing the official documentation, you'll have a reliable, high-performance storage infrastructure ready for production workloads.

Need High-Performance Storage Hardware?

Self-hosting MinIO allows you to build massive scalable data lakes without the extreme egress fees of public clouds. However, object storage is only as good as the drives and network backbone it runs on.

Explore Fit Servers for high-capacity, cost-effective dedicated storage servers tailored for data-heavy workloads. Whether you need a single large-capacity node or a multi-server cluster with lightning-fast NVMe arrays, Fit Servers gives you the raw disk I/O and dedicated bandwidth required to keep your S3 storage fast, secure, and always online.

Configure your storage server today