Deployment guide

MinIO

Overview

MinIO is the de facto open source S3-compatible object storage system. It speaks the AWS S3 wire protocol exactly, so every aws-sdk client, Velero, Restic, BorgBackup, Spark, Trino, ClickHouse, DuckDB and any other S3-aware tool works without modification.

This SecureAnyCloud image runs the latest stable MinIO server on Ubuntu 24.04 on Azure, installed from the official dl.min.io .deb package, with the mc command-line client at /usr/local/bin/mc alongside it. On every new VM, minio-firstboot.service replaces the build-time temporary root credentials with strong per-VM values, so no two VMs ever share root credentials.

What you get:

  • MinIO server installed from the official dl.min.io .deb (latest stable)
  • The mc client at /usr/local/bin/mc for command-line administration
  • minio.service, a systemd unit that starts automatically on boot
  • minio-firstboot.service, a systemd oneshot that rotates MINIO_ROOT_USER and MINIO_ROOT_PASSWORD to per-VM values, restarts MinIO so the new environment is picked up, and writes the credentials to /stage/scripts/minio-credentials.log (mode 0600)
  • Listeners on TCP 9000 (S3 API) and TCP 9001 (Web Console)
  • A single-drive data directory at /mnt/minio-data
  • Binding to all interfaces by default, so your NSG controls actual reach
  • An Ubuntu 24.04 LTS base with the latest security patches applied at build time
  • The Azure Linux Agent for cloud integration and SSH key injection
  • 24/7 SecureAnyCloud support with a guaranteed 24-hour response SLA

Prerequisites

You need:

  • An active Azure subscription
  • A subscription to the MinIO on Ubuntu 24.04 listing on Azure Marketplace
  • An SSH public key for VM authentication
  • A virtual network and subnet in the target region

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for development and small workloads. For production, use Standard_D2s_v3 or larger with attached Premium SSD data disks. Ideally, use 4 or more disks across multiple nodes for erasure-coded resilience.

1

Deploy from the Azure Portal

Open Marketplace in the Azure Portal, search for MinIO, select the SecureAnyCloud publisher entry, and select Create.

On the Networking tab, attach a network security group (NSG) that allows three inbound rules. Allow TCP 22 from your management IP range. Allow TCP 9001 (the Console) from your admin networks. Allow TCP 9000 (the S3 API) from your application networks.

Do not expose the Console (9001) to the public internet. Root credentials are written in plain text on the VM, and an internet-exposed Console makes brute-force attacks trivial. For any public deployment, add TLS at a reverse proxy such as Nginx, Caddy, Apache or Azure Application Gateway.

Select Review + create, wait for validation, then select Create. Deployment takes around two minutes.

2

Deploy from the Azure CLI

Set the variables at the top of the script, then run it. It creates a resource group, a virtual network, an NSG with three rules and the VM.

RG="minio-prod" LOCATION="eastus" VM_NAME="minio-01" ADMIN_USER="azureuser" GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-sac/providers/Microsoft.Compute/galleries/sacGallery/images/minio-ubuntu-24-04/versions/<version>" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create \
  --resource-group "$RG" \
  --name minio-vnet --address-prefix 10.94.0.0/16 \
  --subnet-name minio-subnet --subnet-prefix 10.94.1.0/24 az network nsg create --resource-group "$RG" --name minio-nsg az network nsg rule create \
  --resource-group "$RG" --nsg-name minio-nsg \
  --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" \
  --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create \
  --resource-group "$RG" --nsg-name minio-nsg \
  --name allow-s3-api --priority 110 \
  --source-address-prefixes 10.94.0.0/16 \
  --destination-port-ranges 9000 --access Allow --protocol Tcp az network nsg rule create \
  --resource-group "$RG" --nsg-name minio-nsg \
  --name allow-console --priority 120 \
  --source-address-prefixes "<your-mgmt-cidr>" \
  --destination-port-ranges 9001 --access Allow --protocol Tcp az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username "$ADMIN_USER" --ssh-key-values "$SSH_KEY" \
  --vnet-name minio-vnet --subnet minio-subnet --nsg minio-nsg \
  --public-ip-sku Standard
3

Connect via SSH

Connect to the VM over SSH:

ssh azureuser@<vm-ip>

minio.service is already running, and minio-firstboot.service has already rotated the root credentials.

4

Verify the MinIO service

Check the service status. The expected state is active (running).

sudo systemctl status minio.service --no-pager

Confirm the first-boot sentinel file exists:

sudo test -f /var/lib/sac/data/minio-firstboot.done && echo FIRSTBOOT_DONE

Confirm that both listeners are up:

sudo ss -tln | grep -E ':9000|:9001'

Check the health endpoint:

curl -s http://localhost:9000/minio/health/live echo "exit=$?"
5

Retrieve the root credentials

Print the credentials file as root:

sudo cat /stage/scripts/minio-credentials.log

The file contains:

ROOT_USER=<ROOT_USER> ROOT_PASSWORD=<ROOT_PASSWORD> S3_API_PORT=9000 CONSOLE_PORT=9001

Store both values in your secret store. The file is mode 0600, readable by root only.

6

Sign in to the Console

Open http://<vm-ip>:9001 in your browser. The MinIO Console sign-in page appears.

Sign in with the ROOT_USER and ROOT_PASSWORD from Step 5. After you sign in, MinIO opens the Object Browser.

Recommended: open Identity, then Users, in the left navigation and create per-application accounts. This keeps production workloads from authenticating as the shared root user.

7

Create a bucket

Open Buckets in the left navigation. On a fresh VM, the list is empty.

Select Create Bucket, enter a name, and select Create Bucket again. To do the same from the command line, run:

export ROOT_USER="$(sudo awk -F= '/^ROOT_USER=/{print $2}' /stage/scripts/minio-credentials.log)"
export ROOT_PASS="$(sudo awk -F= '/^ROOT_PASSWORD=/{print $2}' /stage/scripts/minio-credentials.log)" mc alias set local http://127.0.0.1:9000 "${ROOT_USER}" "${ROOT_PASS}" --api S3v4 mc mb local/sac-test
8

Manage users and access keys

Open Identity, then Users, in the left navigation.

Create a user account for each application. Attach the canned readwrite policy or a custom least-privilege policy, and generate a service access key and secret. Use those credentials in your application's S3 client configuration instead of the root credentials.

From the CLI, the same workflow is:

mc admin user add local app-user 'app-strong-password-here' mc admin policy attach local readwrite --user app-user
9

Built-in metrics dashboard

Open Monitoring, then Metrics, for MinIO's built-in metrics dashboard. It plots requests per second, bandwidth, error rates and storage usage.

For longer-term metrics retention, MinIO exposes a Prometheus scrape endpoint at http://<vm-ip>:9000/minio/v2/metrics/cluster, authenticated with the root token. Pair it with the SecureAnyCloud Grafana 12 image and a Prometheus instance for full observability.

10

Round-trip test from the CLI

Upload a small file, download it again and remove it:

echo "sac-roundtrip-ok" > /tmp/probe.txt mc cp /tmp/probe.txt local/sac-test/probe.txt mc cp local/sac-test/probe.txt /tmp/probe-back.txt cat /tmp/probe-back.txt mc rm local/sac-test/probe.txt mc rb local/sac-test

The expected output is sac-roundtrip-ok, followed by clean removals.

11

Connect from application code

Any aws-sdk works. This Python boto3 example lists the buckets:

python3 -c " import boto3 s3 = boto3.client( 's3', endpoint_url='http://<vm-ip>:9000', aws_access_key_id='<ROOT_USER>', aws_secret_access_key='<ROOT_PASSWORD>', region_name='us-east-1', ) print(s3.list_buckets()) "

For production, generate a per-application access key in the Console and use it instead of the root credentials. Open Identity, then Users, select the user, and open Service Accounts.

12

Server components

These are the key files and paths on the VM:

  • MinIO server binary: /usr/local/bin/minio
  • mc client: /usr/local/bin/mc
  • Data directory: /mnt/minio-data
  • Server configuration: /etc/default/minio
  • Systemd unit: /etc/systemd/system/minio.service
  • First-boot script: /usr/local/sbin/minio-firstboot.sh
  • First-boot service: /etc/systemd/system/minio-firstboot.service
  • Credentials file: /stage/scripts/minio-credentials.log
  • First-boot sentinel: /var/lib/sac/data/minio-firstboot.done

Inspect the installed versions:

minio --version mc --version
13

Manage the MinIO service

Check the status:

sudo systemctl status minio.service --no-pager

Stop, start or restart:

sudo systemctl stop minio.service
sudo systemctl start minio.service
sudo systemctl restart minio.service

View the logs (systemd journal):

sudo journalctl -u minio.service --no-pager -n 50
14

Production hardening

The image is single-node and single-drive, which suits development, staging and small workloads. For production, apply the following changes.

  • Use multi-node erasure coding. Use at least 4 drives in a coded set, across one or more nodes. MinIO's distributed mode requires --server <pool> syntax in the start command. Edit MINIO_VOLUMES in /etc/default/minio to point at the multi-drive layout.
  • Front MinIO with TLS. Terminate TLS at a reverse proxy (the SecureAnyCloud nginx-ssl-certbot-ubuntu-24-04 image is purpose-built for this). Alternatively, drop public.crt and private.key into /etc/minio/certs and set MINIO_OPTS="--certs-dir /etc/minio/certs".
  • Restrict the Console (9001). Allow admin networks only, through the NSG.
  • Restrict the API (9000). Allow your application server subnets only, through the NSG.
  • Switch to a separate data disk. Attach a Premium SSD, format it with xfs, mount it at /mnt/minio-data and set ownership to minio-user:minio-user.
15

Troubleshooting

You cannot reach the Console on port 9001

  • Confirm the service is running: sudo systemctl status minio.service
  • Confirm the listeners are bound: sudo ss -tln | grep -E ':9000|:9001'
  • Check the journal: sudo journalctl -u minio.service --no-pager -n 50
  • Confirm the NSG allows TCP 9001 from your client's source IP

You cannot authenticate to the Console

  • Read the credentials again: sudo cat /stage/scripts/minio-credentials.log
  • Confirm the first-boot sentinel exists: ls -la /var/lib/sac/data/minio-firstboot.done
  • If first boot did not run, check its service: sudo systemctl status minio-firstboot.service --no-pager

An S3 client fails with "InvalidAccessKeyId" or "SignatureDoesNotMatch"

  • Confirm the access key is exactly the value of ROOT_USER (not MINIO_ROOT_USER)
  • Confirm the secret is exactly ROOT_PASSWORD, with no whitespace
  • Confirm region_name is set to us-east-1. MinIO accepts any value, but the SDK requires one
  • Confirm endpoint_url matches the server's actual address and port

The service fails to start

  • Check the journal: sudo journalctl -u minio.service --no-pager -n 100
  • Check the filesystem space: df -h /mnt/minio-data
  • Verify the data directory ownership with sudo ls -la /mnt/minio-data. It should be minio-user:minio-user
16

Security recommendations

  • Rotate the root credentials on a schedule. Edit /etc/default/minio and restart minio.service.
  • Create per-application users under Identity, then Users. Never connect application code as root.
  • Restrict the Console port (9001) to admin networks only.
  • Enable TLS before you expose MinIO to anything other than a private VNet.
  • Enable bucket versioning for buckets that hold important data: mc version enable local/<bucket>
  • Set bucket retention policies for compliance-heavy data: mc retention set --default GOVERNANCE 30d local/<bucket>
  • Audit access logs by enabling MinIO's audit webhook or Kafka target.
  • Keep MinIO updated by periodically re-installing the latest .deb from dl.min.io. Data is preserved across upgrades.
  • Shred the credentials file once the root credentials are in your secret store: sudo shred -u /stage/scripts/minio-credentials.log
17

Support and licensing

MinIO is dual-licensed under AGPLv3 (community) and a commercial license from MinIO Inc. SecureAnyCloud ships the community AGPLv3 build. If you redistribute MinIO as part of a closed-source product or SaaS, the AGPLv3 obligations apply, or you can purchase a commercial license from MinIO Inc.

SecureAnyCloud provides commercial support for the SecureAnyCloud image, covering deployment, configuration and integration with other SecureAnyCloud products. This support is separate from the MinIO project itself.

  • Email: sales@secureanycloud.com
  • Website: secureanycloud.com
  • Support hours: 24/7, with a guaranteed 24-hour response SLA

Deploy on Azure

Launch MinIO on Ubuntu 24.04 with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure

Launch MinIO on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure