Self-Hosted MinIO S3 Object Storage on Linux
Cloud

Self-Hosted MinIO S3 Object Storage on Linux

  • Author :Liam K.
  • Date :June 30, 2026
  • Time :18 minutes

MinIO provides an S3-compatible API for object storage on your own infrastructure. It is widely used for backups, media assets, CI artifacts, and application uploads — without vendor lock-in to a single cloud provider. This guide covers a single-node production baseline you can extend to distributed mode later.

Prerequisites

  • Ubuntu 22.04+ or Debian 12 with a dedicated data volume (e.g. /mnt/minio-data)
  • DNS record for s3.example.com pointing to the server
  • At least 4 GB RAM and fast SSD storage for metadata-heavy workloads

Step 1: Create Dedicated User and Data Directory

bash
sudo useradd -r -s /sbin/nologin minio-user || true
sudo mkdir -p /mnt/minio-data
sudo chown -R minio-user:minio-user /mnt/minio-data
sudo chmod 750 /mnt/minio-data

Step 2: Download and Install MinIO Binary

bash
cd /tmp
curl -LO https://dl.min.io/server/minio/release/linux-amd64/minio
sudo install -m 755 minio /usr/local/bin/minio
minio --version

Step 3: Install MinIO Client (mc)

bash
curl -LO https://dl.min.io/client/mc/release/linux-amd64/mc
sudo install -m 755 mc /usr/local/bin/mc
mc --version

Step 4: Configure Environment and systemd Service

bash
sudo tee /etc/default/minio >/dev/null <<'EOF'
MINIO_ROOT_USER="minio-admin"
MINIO_ROOT_PASSWORD="REPLACE_WITH_LONG_RANDOM_PASSWORD"
MINIO_VOLUMES="/mnt/minio-data"
MINIO_OPTS="--console-address :9001"
MINIO_SERVER_URL="https://s3.example.com"
EOF
sudo chmod 600 /etc/default/minio
[...]
Command truncated. Copy to view full command.

Step 5: Put TLS in Front with Caddy or Nginx

Terminate TLS at your reverse proxy and forward to MinIO on localhost port 9000. Example Caddy block:

text
s3.example.com {
    reverse_proxy 127.0.0.1:9000
}

console.s3.example.com {
    reverse_proxy 127.0.0.1:9001
}

Step 6: Configure mc Alias and Create Buckets

bash
mc alias set local https://s3.example.com minio-admin 'REPLACE_WITH_LONG_RANDOM_PASSWORD'
mc mb local/app-uploads
mc mb local/backups
mc anonymous set none local/app-uploads
mc anonymous set none local/backups

Step 7: Create Application IAM Policy

bash
cat > /tmp/app-upload-policy.json <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:ListBucket"],
      "Resource": [
[...]
Command truncated. Copy to view full command.

Step 8: Set Lifecycle Rules

bash
cat > /tmp/lifecycle.json <<'EOF'
{
  "Rules": [
    {
      "ID": "expire-temp-uploads",
      "Status": "Enabled",
      "Filter": { "Prefix": "tmp/" },
      "Expiration": { "Days": 7 }
[...]
Command truncated. Copy to view full command.

Step 9: Verify with aws-cli Compatibility

bash
export AWS_ACCESS_KEY_ID=app-uploader
export AWS_SECRET_ACCESS_KEY=APP_USER_SECRET
export AWS_DEFAULT_REGION=us-east-1

aws --endpoint-url https://s3.example.com s3 ls s3://app-uploads/
echo "health-check" | aws --endpoint-url https://s3.example.com s3 cp - s3://app-uploads/health-check.txt
aws --endpoint-url https://s3.example.com s3 rm s3://app-uploads/health-check.txt

Operations Checklist

  • Monitor disk usage on /mnt/minio-data — object storage failures are often capacity failures.
  • Rotate root and application credentials on a defined schedule.
  • Restrict console access (:9001) to admin IPs or VPN only.
  • Include MinIO data in your backup and restore drill program.
  • Plan erasure coding or distributed mode before you outgrow single-node I/O.

"S3-compatible storage is only production-ready when bucket policies, lifecycle rules, and restore tests are treated as part of the platform — not afterthoughts."

Technical Author

Technical Author - Liam K.
Liam K.

System administrator and technical writer specializing in server infrastructure, security and deployment. Creating comprehensive guides to help you master server administration.