AI Chat

Self-Hosted MinIO Object Storage on Bare Metal: An S3-Compatible Alternative

Dedicated Server Graphic
Ask AI to extract steps & commands from this tutorial:

Why Self-Host Object Storage Instead of Using AWS S3

Most teams reach for AWS S3 by default because it's the API everyone knows. The problem isn't the API — it's the bill. Object storage on public cloud platforms charges for storage and for every byte that leaves the network. For a business pulling backups, serving media, or running an off-site disaster recovery target, those egress fees compound fast and turn a predictable monthly cost into a variable one.

MinIO solves this by giving you the exact same S3 API — the same SDKs, the same aws s3 cp commands, the same tools your developers already use — running on hardware you control. Point any S3-compatible application at your MinIO endpoint instead of s3.amazonaws.com, and nothing else in your stack needs to change.

This guide walks through a production-ready MinIO deployment on a Linux bare-metal dedicated server, with TLS, access policies, and a practical off-site backup use case at the end.

What You'll Need

  • A dedicated server running Ubuntu 24.04 LTS with root or sudo access
  • At least one dedicated disk or partition for object storage (a separate volume from the OS disk is strongly recommended)
  • A domain name or subdomain pointed at the server (for TLS)
  • Basic familiarity with the Linux command line

If you're sizing a server specifically for object storage, prioritise disk throughput and capacity over CPU — MinIO is I/O-bound for most workloads, not compute-bound.

Step 1: Prepare the Storage Disk

Identify the disk you'll dedicate to MinIO and format it:

bash

lsblk
sudo mkfs.xfs /dev/sdb
sudo mkdir -p /mnt/minio-data
sudo mount /dev/sdb /mnt/minio-data
                            

Add the mount to /etc/fstab so it survives a reboot:

bash

echo "/dev/sdb /mnt/minio-data xfs defaults 0 2" | sudo tee -a /etc/fstab
                            

XFS is the filesystem MinIO's own documentation recommends for production deployments, mainly due to its handling of large files and extent-based allocation.

Step 2: Create a Dedicated MinIO User

Never run a storage service as root. Create a system user with no login shell:

bash

sudo useradd -r minio-user -s /sbin/nologin
sudo chown minio-user:minio-user /mnt/minio-data
                            

Step 3: Download and Install MinIO

Download the MinIO binary and make it executable:

bash

wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
sudo mv minio /usr/local/bin/
                            

Create the environment file that defines where data lives and what credentials the server uses:

bash

sudo mkdir -p /etc/minio
sudo nano /etc/default/minio
                            

Add the following, replacing the credentials with strong, unique values:

bash

MINIO_ROOT_USER=your_admin_username
MINIO_ROOT_PASSWORD=a_long_random_password_here
MINIO_VOLUMES="/mnt/minio-data"
MINIO_OPTS="--console-address :9001"
                            

Step 4: Run MinIO as a systemd Service

Create a service file so MinIO starts automatically and restarts on failure:

bash

sudo nano /etc/systemd/system/minio.service
                            

Paste the following configuration into the file:

plaintext

[Unit]
Description=MinIO Object Storage
After=network-online.target
Wants=network-online.target

[Service]
User=minio-user
Group=minio-user
EnvironmentFile=/etc/default/minio
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
                            

Enable and start the service:

bash

sudo systemctl daemon-reload
sudo systemctl enable --now minio
sudo systemctl status minio
                            

The API listens on port 9000 by default; the web console listens on 9001.

Step 5: Secure the Endpoint with TLS

Running object storage without TLS means credentials and data travel in plaintext — not acceptable for production. Place MinIO behind Nginx as a reverse proxy and issue a certificate with Let's Encrypt:

bash

sudo apt install nginx certbot python3-certbot-nginx -y
sudo certbot --nginx -d storage.yourdomain.com
                            

A minimal Nginx server block for the MinIO API:

nginx

server {
    listen 443 ssl;
    server_name storage.yourdomain.com;

    client_max_body_size 0;

    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_buffering off;
    }
}
                            

Alternatively, MinIO can terminate TLS itself by placing certificate files in ~/.minio/certs/ — useful if you want to avoid a reverse-proxy hop entirely for performance-sensitive workloads.

Step 6: Create Buckets and Access Policies

Install the MinIO Client (mc) to manage buckets from the command line:

bash

wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/
mc alias set myminio https://storage.yourdomain.com your_admin_username your_long_random_password
                            

Create a bucket and apply a least-privilege access policy:

bash

mc mb myminio/backups
mc admin user add myminio backup-service a_separate_strong_password
mc admin policy create myminio backup-write-only backup-policy.json
mc admin policy attach myminio backup-write-only --user backup-service
                            

A sample backup-policy.json that allows writes but not deletes:

json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject", "s3:ListBucket"],
      "Resource": ["arn:aws:s3:::backups/*", "arn:aws:s3:::backups"]
    }
  ]
}
                            

This is the same IAM-style policy language AWS S3 uses, so anything you already know about S3 bucket policies applies directly.

Step 7: Use MinIO as an Off-Site Backup Target

If you're already running BorgBackup or a similar deduplicating backup tool on your primary server, MinIO is a natural off-site repository target for a proper 3-2-1 backup strategy: one copy on the production server, one on local/secondary storage, and one off-site.

Because MinIO speaks the S3 protocol, tools like rclone can sync straight to it:

bash

rclone config  # choose 's3' provider, point endpoint at storage.yourdomain.com
rclone sync /local/backup-repo myminio:backups --progress
                            

Running MinIO on a second bare-metal server in a different data centre — for example, syncing from a London server to a Manchester one — gives you genuine geographic redundancy without paying a public cloud provider for every gigabyte that moves.

Discover eServers Dedicated Server Locations

eServers provides reliable dedicated servers across multiple global regions. Whether you need low latency, regional compliance, or proximity to your audience, our wide geographic coverage ensures the perfect hosting environment for your project.

Our Bandwith providers

We are Partners with 15 +

At eServers , we proudly partner with 15+ leading global tech providers to deliver secure, high-performance hosting solutions. These trusted alliances with top hardware, software, and network innovators ensure our clients benefit from modern technology and enterprise-grade reliability.

Hosting Solutions