Self-Hosted MinIO Setup for S3-Compatible Storage

Storing large volumes of data in the cloud is costly, and vendor lock-in hinders growth. We configure a self-hosted S3-compatible storage based on MinIO that fully replicates the Amazon S3 API. Our team delivers the project turnkey—from infrastructure audit to deploying a distributed cluster with erasure coding and ongoing support.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Self-hosted MinIO cuts storage costs by up to 70% compared to AWS S3 for large data volumes. We deploy self-hosted S3-compatible storage that fully replicates the Amazon S3 API. Our engineers have 5+ years of production experience with MinIO and have deployed over 50 distributed clusters for projects with workloads up to 100 TB. MinIO is not just an S3 proxy—it's a full system with erasure coding for fault tolerance. In this article, we'll walk through deploying MinIO on bare-metal or Kubernetes, configuring TLS, access policies, and monitoring. If you need to deploy MinIO in production—start with an assessment of your infrastructure.

Why Distributed MinIO Is Better Than Single-Node for Production

A single-node MinIO can be set up in an hour and is suitable for development, CI/CD caches, and small projects. For production, you need distributed mode with multiple nodes: it provides fault tolerance through erasure coding. A cluster of 4 nodes with two disks each (8 disks) can withstand the loss of up to 4 disks without data loss. MinIO's erasure coding is 2x more storage-efficient than 3x replication in AWS S3, with the same level of fault tolerance. In a typical 50 TB scenario, hardware costs are recouped within 12-18 months, and savings compared to AWS S3 reach 70%.

Parameter Single-Node Distributed (4+ nodes)
Fault tolerance No Erasure coding, up to 50% disks
Performance Limited to one node Linear scalability
Deployment complexity 4–8 hours 2–3 days
Suitable for Dev, CI/CD, caching Production

How MinIO Replaces AWS S3 in a Self-Hosted Environment

MinIO uses the standard S3 API, so any SDK (boto3, AWS SDK for PHP, Java, Go) works without changes. Simply set endpoint_url and use_path_style_endpoint = true for path-style access. This allows you to migrate existing applications to self-hosted MinIO without rewriting code.

Deploying Distributed MinIO: Step-by-Step Guide

Step 1: Prepare Nodes and Disks

Prepare 4 nodes with two additional disks each (e.g., NVMe 500 GB each). Ensure the OS is Ubuntu 22.04 or CentOS 9. On each node, create the minio-user user and mount the disks to /mnt/disk1 and /mnt/disk2.

Step 2: Install MinIO

Download the binary, install, and configure the systemd unit:

Example systemd unit for MinIO
# Installation
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
mv minio /usr/local/bin/
useradd -r minio-user -s /sbin/nologin
chown minio-user:minio-user /mnt/disk1 /mnt/disk2

# systemd unit
cat > /etc/systemd/system/minio.service << 'UNIT'
[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

[Service]
WorkingDirectory=/usr/local/bin/
User=minio-user
Group=minio-user
EnvironmentFile=/etc/minio/minio.env
ExecStartPre=/bin/bash -c "if [ -z "${MINIO_VOLUMES}" ]; then echo "Variable MINIO_VOLUMES not set in /etc/minio/minio.env"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
Restart=always
LimitNOFILE=65536
TasksMax=infinity
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target
UNIT

Step 3: Configure Environment and Start

Create the file /etc/minio/minio.env:

MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=strong-password MINIO_VOLUMES="https://minio{1...4}.internal:9000/mnt/disk{1...2}/minio" MINIO_OPTS="--console-address :9001" MINIO_SITE_NAME=datacenter-1 

Start and enable the service: systemctl start minio && systemctl enable minio.

Step 4: TLS and Security

According to the official MinIO documentation, in production the server must operate only over TLS. Place the certificates:

mkdir -p /etc/minio/certs
cp /etc/letsencrypt/live/minio.company.com/fullchain.pem /etc/minio/certs/public.crt
cp /etc/letsencrypt/live/minio.company.com/privkey.pem /etc/minio/certs/private.key
chown minio-user: /etc/minio/certs/private.key
chmod 600 /etc/minio/certs/private.key

For internal PKI or self-signed certificates, place the CA in /etc/minio/certs/CAs/.

Step 5: Configure Access Policies via mc

MinIO Client (mc) is the main management tool:

mc alias set prod https://minio.company.com:9000 minioadmin пароль
mc mb prod/app-uploads
mc admin user add prod app-service сервисный-пароль
cat > /tmp/app-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": ["arn:aws:s3:::app-uploads/*"]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::app-uploads"]
    }
  ]
}
EOF
mc admin policy create prod app-policy /tmp/app-policy.json
mc admin policy attach prod app-policy --user app-service

Integration with Applications

Python (boto3):

import boto3
s3 = boto3.client(
    's3',
    endpoint_url='https://minio.company.com:9000',
    aws_access_key_id='app-service',
    aws_secret_access_key='сервисный-пароль',
    region_name='us-east-1',
)
s3.upload_file('localfile.pdf', 'app-uploads', 'path/to/remote.pdf')

For Laravel, simply set the endpoint in the config and enable use_path_style_endpoint. use_path_style_endpoint is mandatory—without it, the SDK tries to reach bucket.minio.company.com, which won't work without a wildcard DNS.

Kubernetes: For Kubernetes deployments, use the minio-operator Helm chart and a StatefulSet with dedicated PVCs for each node. This ensures proper recovery after failures.

Monitoring and Observability

MinIO exposes Prometheus-format metrics at /minio/v2/metrics/cluster. Key metrics: minio_cluster_capacity_usable_free_bytes, minio_cluster_nodes_online_total, minio_s3_requests_errors_total. We set up Grafana dashboards from the official repository and alerts based on SLO (availability not lower than 99.9%). For metric collection, we optionally use an OpenTelemetry Collector sidecar container.

What’s Included in Our Work

You receive:

  • A ready distributed MinIO cluster with TLS;
  • Configured access policies and service accounts;
  • Documentation on operations and backup;
  • Integration with your applications (Laravel, Python, Java, Go);
  • Team training on basic administration;
  • Monitoring and alerting via Prometheus/Grafana;
  • 30-day warranty support after launch.

Timeframes

Scenario Time
Single-node MinIO with TLS 4–8 hours
Distributed (4 nodes) with policies 2–3 days
Configuring replication between datacenters +1 day

Cost is calculated individually after an infrastructure audit. We will assess your project in one day. Get a consultation on MinIO setup.

Guarantee and Support

5+ years of production experience with MinIO, 50+ object storage projects. We use a GitOps approach: all configuration is stored in Terraform and Ansible. Guaranteed uptime of 99.9% for distributed clusters. For MinIO backup, you can use mc mirror to another S3-compatible system or rsync. We recommend setting up daily snapshots of configuration and data.

Contact us for a detailed audit of your infrastructure. We will prepare a custom proposal for deploying MinIO. Order an audit of your infrastructure for an accurate cost and timeline estimate.