Skip to content

This is the multi-page printable view of this section. .

Return to the regular view of this page.

Module: MINIO

Deploy Silo S3-compatible object storage with Pigsty’s MINIO compatibility module and use it as a PostgreSQL backup repository.

MINIO is Pigsty’s compatibility module name for S3-compatible object storage. The current role deploys Silo, and minio_type accepts only silo.

Silo preserves the MinIO S3/Admin APIs, MINIO_* environment variables, disk format, and mcli client interface, and can serve as a PostgreSQL pgBackRest backup repository. The module name, parameter prefix, and monitoring job retain the MINIO / minio_* namespace for compatibility with existing inventories and operational entry points.

Important

minio and rustfs are no longer valid minio_type values and fail during identity validation. Before upgrading a MinIO cluster managed by an older release, complete a backup, validate MinIO-to-Silo compatibility, and rehearse rollback. Do not treat package replacement as an already-accepted data migration. External MinIO, RustFS, or other S3 services can still serve as pgBackRest repositories, but the current MINIO role does not manage them.

MINIO is an optional module. When using it as a pgBackRest S3 repository, deploy it before the PGSQL module. TLS certificates and the host baseline come from the NODE / CA capabilities.


Quick Start

The following inventory explicitly defines a single-node Silo cluster. Both minio_cluster and minio_seq are required identity parameters; production inventories should explicitly set minio_type: silo.

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
  vars:
    minio_cluster: minio
    minio_type: silo
./minio.yml -l minio    # Deploy Silo on the minio group

The inventory group name may differ from minio_cluster. Roles calculate actual membership from each host’s minio_cluster identity. Do not define minio_cluster in all.vars, or every host will be treated as an object-storage member.

After deployment, use these entry points:

  • S3 API: https://sss.pigsty:9000 (configure DNS or /etc/hosts explicitly for the domain)
  • Administration UI: https://<node-ip>:9001
  • Command line: mcli ls sss/ (a preconfigured alias is written on the admin node and cluster members)

The default administrator credentials are minioadmin / S3User.MinIO. They are for demos only and must be changed before production deployment.


Deployment Modes

Silo uses the following Pigsty inventory deployment modes:

Mode Description Use Cases
Single-Node Single-Disk (SNSD) Single node, one data directory Development, testing, demos
Single-Node Multi-Disk (SNMD) Single node, multiple disks Resource-constrained small deployments
Multi-Node Single-Disk (MNSD) Multiple nodes, one data drive per node Compact HA deployments
Multi-Node Multi-Disk (MNMD) Multiple nodes with multiple disks per node Recommended for production

minio_data is always a directory path. Distributed and multi-drive deployments require these paths to reside on non-root, persistent filesystems. For example, /data/minio may be a subdirectory of a separately mounted /data filesystem, but not merely a directory on the root filesystem.

The multi-pool expansion semantics of minio_volumes come from the MinIO-compatible interface retained by Silo. Validate operations and rollback against the actual Silo version before production scaling.


Core Capabilities

  • Compatible interface: Silo retains minio_* parameters, the S3 port, TLS, and the mcli provisioning flow
  • HA topologies: Supports single-node, multi-node single-drive, and multi-node multi-drive deployments, with multiple independent clusters in one inventory
  • Backup repository: Can serve as a remote pgBackRest S3 repository
  • Security baseline: Enables HTTPS by default and uses the Pigsty CA to issue a certificate for every instance
  • Observability: Scrapes Silo metrics through /minio/metrics/v3 and provides Grafana dashboards and alerts
  • Operational compatibility: Module name, target directories, monitoring labels, and client aliases retain the MINIO namespace

1 - Usage

Quickly use Silo deployed by the MINIO module through mcli, rclone, and pgBackRest.

After you configure and deploy Silo with the playbook, use this page to access it through the compatible S3 and mcli interfaces.


Deploy Cluster

First, define a single-node, single-disk object-storage cluster in the config inventory and explicitly pin its engine:

minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio, minio_type: silo } }

Then, run the minio.yml playbook provided by Pigsty against the defined group (here minio):

./minio.yml -l minio

Note that deploy.yml automatically creates predefined Silo clusters, so you do not need to run the minio.yml playbook again manually.

For a production multi-node deployment, read Pigsty’s configuration documentation and verify the operational constraints of the Silo version you deploy.


Access Cluster

Production environments should access object storage through a domain name and HTTPS, which is also the default configuration. If you explicitly set minio_https to false, HTTP is available instead. In either case, ensure that the object-storage service domain (default sss.pigsty) points to the service node or load balancer.

  1. You can add static resolution records in node_etc_hosts, or manually modify the /etc/hosts file
  2. You can add a record on the internal DNS server if you already have an existing DNS service
  3. If you have enabled the DNS server on Infra nodes, you can add records in dns_records

For production, we recommend the first method—static DNS records—so object storage does not depend on dynamic DNS.

Point the S3 service domain to the IP address and service port of a Silo node or load balancer. Pigsty uses sss.pigsty as the default S3 service domain and serves it on port 9000. The role does not automatically create a global DNS record for minio_domain; configure resolution explicitly as described above.

Some examples deploy HAProxy on the Silo cluster to expose the service; those templates use port 9002 as the unified service port.


Adding Alias

To access the Silo cluster with the mcli client, first configure a server alias:

mcli alias ls  # list minio alias (default is sss)
mcli alias set sss https://sss.pigsty:9000 minioadmin S3User.MinIO            # root user
mcli alias set sss https://sss.pigsty:9002 minioadmin S3User.MinIO            # root user, using load balancer port 9002

mcli alias set pgbackrest https://sss.pigsty:9000 pgbackrest S3User.Backup    # use backup user

After a full minio.yml run with minio_provision enabled, the role configures the default alias for the Ansible execution user on every Infra node and every actual object-storage member discovered by minio_cluster. A host in both sets is configured only once.

For the full mcli command reference, see the upstream MinIO Client documentation.

Note: Use Your Actual Password

The password S3User.MinIO in the above examples is the Pigsty default. If you modified minio_secret_key during deployment, please use your actual configured password.


User Management

You can manage Silo application users with mcli. Default provisioning already creates pgbackrest, s3user_meta, and s3user_data; the example below creates one additional user and attaches the generated policy for the default data bucket:

mcli admin user list sss
set +o history
mcli admin user add sss appuser 'Replace.With.Strong.Password'
mcli admin policy attach sss data --user=appuser
set -o history

Bucket Management

You can perform CRUD operations on buckets in Silo:

mcli ls sss/                         # list all buckets on alias 'sss'
mcli mb --ignore-existing sss/hello  # create a bucket named 'hello'
mcli rb --force sss/hello            # force delete the 'hello' bucket

Object Management

You can also perform CRUD operations on objects within buckets. For details, please refer to the official documentation: Object Management

mcli cp /www/pigsty/* sss/data/      # upload local repo content to the default data bucket
mcli cp sss/data/plugins.tgz /tmp/   # download file from Silo
mcli ls sss/data                     # list all files in the data bucket
mcli rm sss/data/plugins.tgz         # delete a specific file in the data bucket
mcli cat sss/data/repo_complete      # view file content in the data bucket

Using rclone

The Pigsty repository provides rclone, a convenient multi-cloud object-storage client that can access Silo.

yum install rclone;  # EL-compatible systems
apt install rclone;  # Debian/Ubuntu systems

mkdir -p ~/.config/rclone/;
tee ~/.config/rclone/rclone.conf > /dev/null <<EOF
[sss]
type = s3
access_key_id = minioadmin
secret_access_key = S3User.MinIO
endpoint = https://sss.pigsty:9000
EOF

rclone ls sss:/
Note: HTTPS and Certificate Trust

If Silo uses HTTPS (the default), ensure that the client trusts Pigsty’s CA certificate (/etc/pki/ca.crt), or add no_check_certificate = true to the rclone configuration to skip certificate verification (not recommended for production).


Configure Backup Repository

In Pigsty, the MINIO module’s primary use case is as an S3 backup repository for pgBackRest. When you set pgbackrest_method to minio, the PGSQL module uses the S3-compatible repository preset with that name. Silo deployed by the MINIO module works directly with this preset.

pgbackrest_method: local          # pgbackrest repo method: local,minio,[user-defined...]
pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
  local:                          # default pgbackrest repo with local posix fs
    path: /pg/backup              # local backup directory, `/pg/backup` by default
    retention_full_type: count    # retention full backups by count
    retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
  minio:                          # optional minio repo for pgbackrest
    type: s3                      # Silo uses the S3-compatible repository type
    s3_endpoint: sss.pigsty       # Silo endpoint domain, `sss.pigsty` by default
    s3_region: us-east-1          # compatibility region, `us-east-1` by default
    s3_bucket: pgsql              # backup bucket, `pgsql` by default
    s3_key: pgbackrest            # pgBackRest access key
    s3_key_secret: S3User.Backup  # pgBackRest secret key
    s3_uri_style: path            # use path-style rather than host-style URIs
    path: /pgbackrest             # backup path, `/pgbackrest` by default
    storage_port: 9000            # Silo service port, 9000 by default
    storage_ca_file: /pg/cert/ca.crt  # CA path, `/pg/cert/ca.crt` by default
    bundle: y                     # bundle small files into a single file
    cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
    cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
    retention_full_type: time     # retain full backups by time on the remote repository
    retention_full: 14            # keep full backup for last 14 days

If you use a multi-node Silo cluster behind a load balancer, adjust s3_endpoint and storage_port accordingly.




2 - Configuration

Deploy Silo with the MINIO module and configure reliable S3 access in single-node, multi-drive, or multi-node modes.

Before deploying the MINIO module, define a Silo object-storage cluster in the config inventory. The current role requires minio_type: silo and supports these inventory deployment modes:

SNSD is suitable for development and testing, three-node MNSD for resource-constrained compact HA, and MNMD for production environments with higher capacity, throughput, and drive-redundancy requirements. SNMD handles drive failures within one server but cannot tolerate losing the server.

Silo can also use multi-pool deployment for expansion, or you can deploy multiple clusters.

With a multi-node cluster, any member can serve the S3 API, so the best practice is to place load balancing and high-availability service access in front of it.


Backend Selection

minio_type: silo   # the only valid value

minio_type is retained as a selector for future expansion, but the current deployment and removal roles accept only silo. It maps to the silo package, silo.service, /etc/default/silo, and ~/.minio/certs/. To support in-place migration, silo.service first reads legacy /etc/default/minio and then the higher-priority /etc/default/silo; it also conflicts with the old minio.service. New deployments should maintain only the Silo configuration file.

Legacy inventories with minio_type: minio or minio_type: rustfs fail identity validation. Before upgrading an existing MinIO deployment, validate MinIO-to-Silo data compatibility, backups, and rollback. References below to MinIO topology terms and upstream links describe interfaces retained by Silo; they do not mean that the current role still installs the minio package.


Core Parameters

Pigsty uses minio_volumes to describe members and disks and renders it as Silo’s MINIO_VOLUMES. The role derives this value from inventory by default and also allows an explicit override.

  • Single-Node Single-Disk: minio_volumes points to a regular local directory derived from minio_data, defaulting to /data/minio.
  • Single-Node Multi-Disk: minio_volumes points to a sequence of local mount points derived from minio_data, for example /data{1...4}.
  • Multi-Node Single-Disk: minio_volumes points to one data path on each server, for example https://minio-{1...3}.pigsty:9000/data/minio.
  • Multi-Node Multi-Disk: minio_volumes points to mount points across multiple servers, automatically generated from two parts:
    • First, use minio_data to specify the disk mount point sequence for each cluster member /data{1...4}
    • Also use minio_node to specify the node naming pattern ${minio_cluster}-${minio_seq}.pigsty
  • Multi-Pool: Explicitly set minio_volumes to assign nodes to each storage pool.

Storage Paths and Mounts

minio_data is a filesystem directory, not a raw block device. Format and mount a local disk, cloud volume, separate partition, or LVM logical volume first, then give Silo the mount point or a directory beneath it. Do not put /dev/sdb in minio_data.

The MINIO role creates data directories and sets ownership and permissions, but it does not format or persistently mount production storage. Topologies impose different requirements on the backing filesystem:

  • Single-node single-disk may use a regular directory on the root filesystem, but only for development, testing, and demos.
  • Every path in a single-node multi-disk deployment should map to a separate filesystem. Multiple directories on one drive do not create multiple drive failure domains.
  • Multi-node distributed Silo detects and rejects data paths on the root filesystem with drive is part of root drive, will not be used.

Therefore, /data/minio may be a regular subdirectory when /data is a separately mounted persistent filesystem. If /data is merely a directory under /, it does not satisfy the distributed-storage requirement. A bind mount backed by the root filesystem does not create a new drive failure domain either.

Inspect the actual mounts before deployment:

findmnt -T /
findmnt -T /data/minio

The second command should report a separate /data or /data/minio mount rather than /. Production mounts should also be persisted in /etc/fstab or an equivalent mechanism, and drives in one storage pool should have similar capacities.


Single-Node Single-Disk

SNSD mode, compatible topology reference: MinIO Single-Node Single-Drive

In Pigsty, defining a singleton Silo instance is straightforward:

# 1 node, 1 data directory
minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio, minio_type: silo } }

In single-node mode, the required identity parameters are minio_seq and minio_cluster, which uniquely identify each object-storage instance.

Single-node single-disk mode is for development purposes only, so you can use a regular directory as the data directory, specified by minio_data, defaulting to /data/minio.

When using Silo, we strongly recommend accessing it through a statically resolved domain name. For example, if minio_domain uses the default sss.pigsty, you can add a static resolution on all nodes to facilitate access to this service.

node_etc_hosts: ["10.10.10.10 sss.pigsty"] # domain name for accessing Silo from all nodes (required)
SNSD is for Development Only

Single-node single-disk mode should only be used for development, testing, and demo purposes, as it cannot tolerate any hardware failure and does not benefit from multi-disk performance improvements. For production, use Multi-Node Multi-Disk mode.


Single-Node Multi-Disk

SNMD mode, compatible topology reference: MinIO Single-Node Multi-Drive

To use multiple disks on a single node, the operation is similar to Single-Node Single-Disk, but you need to specify minio_data in the format {{ prefix }}{x...y}, which defines a series of disk mount points.

minio:
  hosts: { 10.10.10.10: { minio_seq: 1 } }
  vars:
    minio_cluster: minio         # required object-storage cluster identity
    minio_data: '/data{1...4}'   # minio data dir(s), use {x...y} to specify multi drivers
Use Real Disk Mount Points

Every SNMD data path must reside on a separate filesystem. If multiple paths resolve to the same filesystem, Silo refuses to treat them as separate drives. XFS is recommended for production; the Vagrant test setup can also prepare ext4 data drives when XFS tools are unavailable.

For example, the Vagrant object-storage sandbox defines a single-node Silo cluster with four disks: /data1, /data2, /data3, and /data4. Before starting Silo, mount them correctly and format them with xfs:

mkfs.xfs /dev/vdb; mkdir /data1; mount -t xfs /dev/vdb /data1;   # mount disk 1...
mkfs.xfs /dev/vdc; mkdir /data2; mount -t xfs /dev/vdc /data2;   # mount disk 2...
mkfs.xfs /dev/vdd; mkdir /data3; mount -t xfs /dev/vdd /data3;   # mount disk 3...
mkfs.xfs /dev/vde; mkdir /data4; mount -t xfs /dev/vde /data4;   # mount disk 4...

Disk mounting is part of server provisioning and beyond Pigsty’s scope. Mounted disks should be written to /etc/fstab for auto-mounting after server restart.

/dev/vdb /data1 xfs defaults,noatime,nodiratime 0 0
/dev/vdc /data2 xfs defaults,noatime,nodiratime 0 0
/dev/vdd /data3 xfs defaults,noatime,nodiratime 0 0
/dev/vde /data4 xfs defaults,noatime,nodiratime 0 0

SNMD mode can utilize multiple disks on a single machine to provide higher performance and capacity, and tolerate partial disk failures. However, single-node mode cannot tolerate entire node failure, and you cannot add new nodes at runtime, so we do not recommend using SNMD mode in production unless you have special reasons.


Multi-Node Single-Disk

MNSD uses one data drive on each of several servers. The following inventory defines a three-node, single-drive Silo cluster, which is also the storage topology used by ha/trio:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
  vars:
    minio_cluster: minio
    minio_type: silo
    minio_data: /data/minio

The role generates https://minio-{1...3}.pigsty:9000/data/minio. The three paths reside on three different servers, and /data/minio on every server must be backed by a non-root, persistent filesystem.

A three-drive set uses EC:1 by default: each object is split into two data shards and one parity shard. Read and write quorum are both two, so one node or one data drive may be unavailable. With equal-size drives, usable capacity is about two-thirds of raw capacity before filesystem and metadata overhead, and is limited by the smallest drive.

This is a resource-efficient compact HA topology that removes the single object-storage node as a failure point, but each node still has only one data drive. Use Multi-Node Multi-Disk when capacity, throughput, or per-node drive redundancy requirements are higher.

An existing single-node storage pool cannot be converted in place by adding two members. Create a new three-node cluster, migrate the objects, and switch client endpoints.


Multi-Node Multi-Disk

MNMD mode, compatible topology reference: MinIO Multi-Node Multi-Drive

In addition to using minio_data to specify disks as in Single-Node Multi-Disk mode, use minio_node to specify the multi-node naming pattern.

For example, the following configuration defines a four-node Silo cluster with four disks per node:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }  # actual nodename: minio-1.pigsty
    10.10.10.11: { minio_seq: 2 }  # actual nodename: minio-2.pigsty
    10.10.10.12: { minio_seq: 3 }  # actual nodename: minio-3.pigsty
    10.10.10.13: { minio_seq: 4 }  # actual nodename: minio-4.pigsty
  vars:
    minio_cluster: minio
    minio_data: '/data{1...4}'                         # 4-disk per node
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern

The minio_node parameter specifies the MINIO module’s internal node-name pattern, used to generate a unique name for each node. By default, the node name is ${minio_cluster}-${minio_seq}.pigsty, where ${minio_cluster} is the cluster name and ${minio_seq} is the node sequence number. Instance names are automatically written to /etc/hosts on each Silo node so cluster members can identify and reach one another.

In this case, the derived minio_volumes is https://minio-{1...4}.pigsty:9000/data{1...4}, identifying four drives on four nodes; the role writes it to Silo’s compatible environment variable. You can set minio_volumes directly on the object-storage cluster to override the automatically generated value. However, this is usually not necessary as Pigsty will automatically generate it based on the config inventory.


Multi-Pool

Silo retains the compatible ability to scale by adding new storage pools. In Pigsty, explicitly set minio_volumes to assign nodes to each pool.

For example, suppose you created the Silo cluster from the Multi-Node Multi-Disk example and now want to add another four-node storage pool.

You need to directly override the minio_volumes parameter:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
    10.10.10.13: { minio_seq: 4 }

    10.10.10.14: { minio_seq: 5 }
    10.10.10.15: { minio_seq: 6 }
    10.10.10.16: { minio_seq: 7 }
    10.10.10.17: { minio_seq: 8 }
  vars:
    minio_cluster: minio
    minio_data: "/data{1...4}"
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern
    minio_volumes: 'https://minio-{1...4}.pigsty:9000/data{1...4} https://minio-{5...8}.pigsty:9000/data{1...4}'

Here, the two space-separated values represent two storage pools, each with four nodes and four disks per node. For details, see Administration: Cluster Expansion.


Multiple Clusters

You can deploy new nodes as an independent Silo cluster. The following configuration declares two object-storage clusters with different identities:

minio1:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
    10.10.10.13: { minio_seq: 4 }
  vars:
    minio_cluster: minio2
    minio_data: "/data{1...4}"

minio2:
  hosts:
    10.10.10.14: { minio_seq: 5 }
    10.10.10.15: { minio_seq: 6 }
    10.10.10.16: { minio_seq: 7 }
    10.10.10.17: { minio_seq: 8 }
  vars:
    minio_cluster: minio2
    minio_data: "/data{1...4}"
    minio_alias: sss2
    minio_domain: sss2.pigsty
    minio_endpoint: sss2.pigsty:9000

minio_cluster has no default and must be defined for every cluster. Multiple clusters must also use distinct minio_alias, minio_domain, and minio_endpoint values, or shared client aliases and domains on INFRA nodes will overwrite one another. The Ansible group name may differ from minio_cluster; roles discover members across the inventory by identity.


Expose Service

Silo serves the S3 API on port 9000 by default. A multi-node cluster can be accessed through any member.

Service access falls under the scope of the NODE module, and we’ll provide only a basic introduction here.

High-availability access to a multi-node object-storage cluster can use L2 VIP or HAProxy. For example, bind an L2 VIP with keepalived, or expose the S3 service through the haproxy component provided by the NODE module.

# object-storage cluster with 4 nodes and 4 drives per node
minio:
  hosts:
    10.10.10.10: { minio_seq: 1 , nodename: minio-1 }
    10.10.10.11: { minio_seq: 2 , nodename: minio-2 }
    10.10.10.12: { minio_seq: 3 , nodename: minio-3 }
    10.10.10.13: { minio_seq: 4 , nodename: minio-4 }
  vars:
    minio_cluster: minio
    minio_data: '/data{1...4}'
    minio_buckets: [ { name: pgsql }, { name: infra }, { name: redis } ]
    minio_users:
      - { access_key: dba , secret_key: S3User.DBA, policy: consoleAdmin }
      - { access_key: pgbackrest , secret_key: S3User.SomeNewPassWord , policy: readwrite }

    # bind a node l2 vip (10.10.10.9) to minio cluster (optional)
    node_cluster: minio
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.9
    vip_interface: eth1

    # expose minio service with haproxy on all nodes
    haproxy_services:
      - name: minio                    # [REQUIRED] service name, unique
        port: 9002                     # [REQUIRED] service port, unique
        balance: leastconn             # [OPTIONAL] load balancer algorithm
        options:                       # [OPTIONAL] minio health check
          - option httpchk
          - option http-keep-alive
          - http-check send meth OPTIONS uri /minio/health/live
          - http-check expect status 200
        servers:
          - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

For example, the configuration above enables HAProxy on every Silo node, exposes the S3 service on port 9002, and binds a Layer 2 VIP to the cluster. Resolve sss.pigsty to VIP 10.10.10.9 and access port 9002; if a node fails, the VIP moves to another node.

In this case, also update global domain resolution and minio_endpoint so the mcli alias written to management nodes uses the new endpoint:

minio_endpoint: https://sss.pigsty:9002   # Override the default: https://sss.pigsty:9000
node_etc_hosts: ["10.10.10.9 sss.pigsty"] # Other nodes will use the sss.pigsty domain to access Silo

Dedicated Load Balancer

Pigsty allows using a dedicated load balancer server group instead of the cluster itself to run VIP and HAProxy. For example, the ha/simu template uses this approach.

proxy:
  hosts:
    10.10.10.18 : { nodename: proxy1 ,node_cluster: proxy ,vip_interface: eth1 ,vip_role: master }
    10.10.10.19 : { nodename: proxy2 ,node_cluster: proxy ,vip_interface: eth1 ,vip_role: backup }
  vars:
    vip_enabled: true
    vip_address: 10.10.10.20
    vip_vrid: 20

    haproxy_services:      # expose minio service : sss.pigsty:9000
      - name: minio        # [REQUIRED] service name, unique
        port: 9000         # [REQUIRED] service port, unique
        balance: leastconn # Use leastconn algorithm and minio health check
        options: [ "option httpchk", "option http-keep-alive", "http-check send meth OPTIONS uri /minio/health/live", "http-check expect status 200" ]
        servers:           # reload service with ./node.yml -t haproxy_config,haproxy_reload
          - { name: minio-1 ,ip: 10.10.10.21 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.22 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.23 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-4 ,ip: 10.10.10.24 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-5 ,ip: 10.10.10.25 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

In this case, point sss.pigsty to the load balancer and update minio_endpoint so the mcli alias on management nodes uses that endpoint:

minio_endpoint: https://sss.pigsty:9002    # overwrite the defaults: https://sss.pigsty:9000
node_etc_hosts: ["10.10.10.20 sss.pigsty"] # domain name for accessing Silo from all nodes (required)

Access Service

To access the Silo service exposed through HAProxy from PGSQL, add a repository definition to pgbackrest_repo:

# New HA S3 repository definition, replacing the previous single-node configuration
minio_ha:
  type: s3
  s3_endpoint: minio-1.pigsty   # endpoint can be any load balancer or a domain pointing to one of the nodes
  s3_region: us-east-1          # you can use external domain name: sss.pigsty, which resolves to any member (`minio_domain`)
  s3_bucket: pgsql              # backup bucket name
  s3_key: pgbackrest            # use a dedicated password for Silo's pgbackrest user
  s3_key_secret: S3User.SomeNewPassWord
  s3_uri_style: path
  path: /pgbackrest
  storage_port: 9002            # Use load balancer port 9002 instead of default 9000 (direct access)
  storage_ca_file: /etc/pki/ca.crt
  bundle: y
  cipher_type: aes-256-cbc      # Better using a new cipher password for your production environment
  cipher_pass: pgBackRest.With.Some.Extra.PassWord.And.Salt.${pg_cluster}
  retention_full_type: time
  retention_full: 14

Expose Console

Silo provides an administration UI on port 9001 by default, controlled by minio_admin_port.

Exposing the administration interface externally may pose security risks. If required, add Silo to infra_portal and refresh the Nginx configuration.

# ./infra.yml -t nginx
infra_portal:
  home         : { domain: h.pigsty }
  # Object-storage administration UI requires HTTPS / WebSocket
  minio        : { domain: m.pigsty     ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }
  minio10      : { domain: m10.pigsty   ,endpoint: "10.10.10.10:9001" ,scheme: https ,websocket: true }
  minio11      : { domain: m11.pigsty   ,endpoint: "10.10.10.11:9001" ,scheme: https ,websocket: true }
  minio12      : { domain: m12.pigsty   ,endpoint: "10.10.10.12:9001" ,scheme: https ,websocket: true }
  minio13      : { domain: m13.pigsty   ,endpoint: "10.10.10.13:9001" ,scheme: https ,websocket: true }

DO NOT expose an unencrypted object-storage administration UI in production.

You will usually need an m.pigsty record in DNS or local /etc/hosts to access the Silo administration page.

Meanwhile, if you are using Pigsty’s self-signed CA rather than a proper public CA, you usually need to manually trust the CA or certificate to skip the “insecure” warning in the browser.




3 - Parameters

The MINIO module exposes 22 parameters for deploying, configuring, and removing Silo object-storage clusters.

The MINIO module exposes 22 public parameters in two groups:

  • MINIO: 19 parameters for deploying Silo object-storage clusters
  • MINIO_REMOVE: 3 parameters controlling object-storage cluster removal
Architecture Change: Pigsty v3.6+

Since Pigsty v3.6, the minio.yml playbook no longer includes removal functionality. Removal-related parameters have been migrated to the dedicated minio_remove role and minio-rm.yml playbook.


Parameter Overview

The MINIO group configures a Silo object-storage cluster, including identity, storage paths, ports, credentials, and bucket/user provisioning.

Parameter Type Level Description
minio_type enum G/C Reserved backend selector; currently accepts only silo
minio_seq int I minio instance identifier, REQUIRED
minio_cluster string C Required object-storage cluster identity
minio_user username C minio os user, minio by default
minio_https bool G/C Enable HTTPS for object storage? true by default
minio_node string C minio node name pattern
minio_data path C minio data dir, use {x...y} for multiple disks
minio_volumes string C minio core parameter for nodes and disks, auto-gen
minio_domain string G minio external domain, sss.pigsty by default
minio_port port C minio service port, 9000 by default
minio_admin_port port C minio console port, 9001 by default
minio_access_key username C root access key, minioadmin by default
minio_secret_key password C root secret key, S3User.MinIO by default
minio_extra_vars string C extra environment variables for minio server
minio_provision bool G/C run minio provisioning tasks? true by default
minio_alias string G minio client alias for the deployment
minio_endpoint string C endpoint for the minio client alias
minio_buckets bucket[] C list of minio buckets to be created
minio_users user[] C list of minio users to be created

The MINIO_REMOVE group controls object-storage cluster removal, including safeguards, data cleanup, and package removal.

Parameter Type Level Description
minio_safeguard bool G/C/A prevent accidental removal? false by default
minio_rm_data bool G/C/A remove Silo data during removal? true by default
minio_rm_pkg bool G/C/A uninstall Silo and mcli? false by default

The minio_volumes and minio_endpoint are auto-generated parameters, but you can explicitly override them.


Defaults

MINIO: 19 public parameters, defined in roles/minio/defaults/main.yml

#-----------------------------------------------------------------
# SILO
#-----------------------------------------------------------------
minio_type: silo                  # reserved object-storage backend selector; currently accepts only silo
#minio_seq: 1                     # minio instance identifier, REQUIRED
#minio_cluster: minio             # required minio cluster identity
minio_user: minio                 # minio os user, `minio` by default
minio_https: true                 # enable HTTPS for Silo? true by default
minio_node: '${minio_cluster}-${minio_seq}.pigsty' # minio node name pattern
minio_data: '/data/minio'         # minio data dir, use `{x...y}` for multiple disks
#minio_volumes:                   # minio core parameter, auto-generated if not specified
minio_domain: sss.pigsty          # minio external domain, `sss.pigsty` by default
minio_port: 9000                  # minio service port, 9000 by default
minio_admin_port: 9001            # minio console port, 9001 by default
minio_access_key: minioadmin      # root access key, `minioadmin` by default
minio_secret_key: S3User.MinIO    # root secret key, `S3User.MinIO` by default
minio_extra_vars: ''              # extra environment variables for minio server
minio_provision: true             # run minio provisioning tasks?
minio_alias: sss                  # minio client alias for the deployment
#minio_endpoint: https://sss.pigsty:9000 # endpoint for alias, auto-generated if not specified
minio_buckets:                    # list of minio buckets to be created
  - { name: pgsql }
  - { name: meta ,versioning: true }
  - { name: data }
minio_users:                      # list of minio users to be created
  - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
  - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
  - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

MINIO_REMOVE: 3 parameters, defined in roles/minio_remove/defaults/main.yml

#-----------------------------------------------------------------
# MINIO_REMOVE
#-----------------------------------------------------------------
minio_safeguard: false            # prevent accidental removal? false by default
minio_rm_data: true               # remove minio data during removal? true by default
minio_rm_pkg: false               # uninstall minio packages during removal? false by default
# MINIO (reference)
minio_type: silo                  # object-storage engine; currently must be silo

MINIO

This section contains parameters for the minio role, used by the minio.yml playbook.

minio_type

Parameter: minio_type, Type: enum, Level: G/C

This reserved object-storage backend selector defaults to—and currently accepts only—silo. Silo retains the MinIO S3/Admin APIs, MINIO_* environment variables, and disk format.

minio and rustfs are no longer valid values and fail during role identity validation. Before upgrading a legacy MinIO cluster to v4.5, independently validate backups, MinIO-to-Silo data compatibility, and rollback; changing this parameter does not migrate data.

Both the deployment and removal roles default minio_type to silo. A minio-rm.yml run still requires the minio_cluster and minio_seq identity parameters and remains subject to minio_safeguard and the data/package cleanup switches; the engine default does not bypass these removal guards.


minio_seq

Parameter: minio_seq, Type: int, Level: I

Object-storage instance identifier, a required identity parameter. No default value—you must assign it manually.

Best practice is to start from 1, increment by 1, and never reuse previously assigned sequence numbers. The sequence number, together with the cluster name minio_cluster, uniquely identifies each object-storage instance (e.g., minio-1).

In multi-node deployments, sequence numbers are also used to generate node names, which are written to the /etc/hosts file for static resolution.


minio_cluster

Parameter: minio_cluster, Type: string, Level: C

Object-storage cluster name. This parameter is required and has no default. Use it to distinguish membership and monitoring identity when deploying multiple clusters.

The cluster name, together with the sequence number minio_seq, uniquely identifies each object-storage instance. For example, with cluster name minio and sequence 1, the instance name is minio-1.

The role finds members across the entire inventory by each host’s minio_cluster value, so the Ansible group name may differ from the cluster identity. Define this parameter explicitly in the object-storage group’s cluster variables; do not define it in all.vars, which would mark every host as a MINIO module member.

For multiple clusters, also set distinct minio_alias, minio_domain, and minio_endpoint values to avoid shared aliases and domain-name conflicts.


minio_user

Parameter: minio_user, Type: username, Level: C

Object-storage operating system user, default is minio.

Silo runs as this user, and its certificates are stored under ~/.minio/certs/.


minio_https

Parameter: minio_https, Type: bool, Level: G/C

Enable HTTPS for the object-storage service? Default is true.

Pigsty’s default pgBackRest minio repository preset uses HTTPS and validates the certificate with /etc/pki/ca.crt, so keep this parameter true when using the defaults. pgBackRest itself does not require Silo to use HTTPS; if you explicitly switch to HTTP, you must also update the storage TLS options in pgbackrest_repo rather than changing only this parameter.

When HTTPS is enabled, Pigsty automatically issues certificates for the selected server, containing the domain specified in minio_domain and the IP addresses of each node.


minio_node

Parameter: minio_node, Type: string, Level: C

Object-storage node-name pattern used for multi-node single-disk and multi-node multi-disk deployments.

Default value: ${minio_cluster}-${minio_seq}.pigsty, which uses the instance name plus .pigsty suffix as the default node name.

The domain pattern specified here generates node names, which are written to /etc/hosts on all Silo nodes.


minio_data

Parameter: minio_data, Type: path, Level: C

Silo data directory, default value: /data/minio. Set this parameter to a filesystem directory, not a raw block device such as /dev/sdb. The MINIO role creates the directory and sets its permissions, but does not format or mount production data drives.

Single-node single-disk may use a regular directory on the root filesystem for development. Multi-node single-disk, multi-node multi-disk, and single-node multi-disk deployments should use independent, persistent, non-root filesystems. Distributed Silo rejects data paths on the root filesystem.

/data/minio may be a subdirectory of a separately mounted /data filesystem. If /data is only a directory under /, it is still on the root drive. For multi-drive deployments, use {x...y} notation for multiple mount points, such as /data{1...4}/minio; every expanded path should map to a separate filesystem.

See Configuration: Storage Paths and Mounts for the complete requirements and verification commands.


minio_volumes

Parameter: minio_volumes, Type: string, Level: C

Silo core volume parameter. It is unset by default and generated with this rule:

minio_volumes: "{% if minio_cluster_size|int > 1 %}https://{{ minio_node|replace('${minio_cluster}', minio_cluster)|replace('${minio_seq}',minio_seq_range) }}:{{ minio_port|default(9000) }}{% endif %}{{ minio_data }}"
  • In single-node deployment (single or multi-drive), minio_volumes directly uses the minio_data value.
  • In multi-node deployment, minio_volumes uses minio_node, minio_port, and minio_data to generate multi-node addresses.
  • In multi-pool deployment, you typically need to explicitly specify and override minio_volumes to define multiple node pool addresses.

When specifying this parameter, ensure the values are consistent with minio_node, minio_port, and minio_data.


minio_domain

Parameter: minio_domain, Type: string, Level: G

Silo service domain name, default is sss.pigsty.

Clients can access the Silo S3 service through this domain. The name is included in the SAN (Subject Alternative Name) of certificates issued by the role, but the MINIO role does not automatically create a DNS record for minio_domain.

Add an explicit record through node_etc_hosts or dns_records, pointing it to a Silo node IP for a single-node deployment or to a load-balancer VIP for a multi-node deployment.


minio_port

Parameter: minio_port, Type: port, Level: C

Silo service port, default is 9000.

This is the Silo S3 API listening port. Clients access object storage through this port, which is also used for inter-node communication in multi-node deployments.


minio_admin_port

Parameter: minio_admin_port, Type: port, Level: C

Silo console port, default is 9001.

This is the listening port for Silo’s web management console, available at https://<minio-ip>:9001.

To expose the Silo console through Nginx, add it to infra_portal. The console requires HTTPS and WebSocket support.


minio_access_key

Parameter: minio_access_key, Type: username, Level: C

Root access key (username), default is minioadmin.

This is the Silo super-administrator username with full access to every bucket and object. Change this default in production.


minio_secret_key

Parameter: minio_secret_key, Type: password, Level: C

Root secret key (password), default is S3User.MinIO.

This is the Silo super-administrator password, used together with minio_access_key.

Security Warning: Change the default password!

Using default passwords is a high-risk behavior! Make sure to change this password in your production deployment.

Tip: ./configure -g randomizes default passwords recognized by the configuration wizard. See the Default Credentials Checklist for the complete scope.


minio_extra_vars

Parameter: minio_extra_vars, Type: string, Level: C

Extra environment variables passed to Silo. Silo retains the MINIO_* variable names.

Default is an empty string. You can use multiline strings to pass multiple environment variables:

minio_extra_vars: |
  MINIO_BROWSER_REDIRECT_URL=https://minio.example.com
  MINIO_SERVER_URL=https://s3.example.com

minio_provision

Parameter: minio_provision, Type: bool, Level: G/C

Run Silo provisioning tasks? Default is true.

When enabled, Pigsty automatically creates the buckets and users defined in minio_buckets and minio_users. Set this to false if you don’t need automatic provisioning of these resources.


minio_alias

Parameter: minio_alias, Type: string, Level: G

mcli client alias for the local Silo cluster, default value: sss.

When minio_provision is enabled, this alias is written to the mcli configuration file (~/.mcli/config.json) for the Ansible execution user on every Infra node and Silo member. Hosts in both groups are configured only once. You can then use mcli <alias> commands directly, for example mcli ls sss/.

If deploying multiple Silo clusters, specify a different alias for each cluster to avoid conflicts.


minio_endpoint

Parameter: minio_endpoint, Type: string, Level: C

Endpoint for the client alias. If specified, minio_endpoint (for example, https://sss.pigsty:9002) replaces the automatically assembled <scheme>://<minio_domain>:<minio_port> endpoint for aliases on Infra nodes and Silo members.

mcli alias set {{ minio_alias }} {% if minio_endpoint is defined and minio_endpoint != '' %}{{ minio_endpoint }}{% else %}{% if minio_https|bool %}https{% else %}http{% endif %}://{{ minio_domain }}:{{ minio_port }}{% endif %} {{ minio_access_key }} {{ minio_secret_key }}

The role runs this command as the Ansible execution user on Infra nodes and Silo members.

minio_buckets

Parameter: minio_buckets, Type: bucket[], Level: C

List of Silo buckets to create by default:

minio_buckets:
  - { name: pgsql }
  - { name: meta ,versioning: true }
  - { name: data }

Three default buckets are created with different purposes and policies:

  • pgsql bucket: Used by default for PostgreSQL pgBackREST backup storage.
  • meta bucket: Open bucket with versioning enabled, suitable for storing important metadata requiring version management.
  • data bucket: Open bucket for other purposes, e.g., Supabase templates may use this bucket for business data.

Each bucket has a corresponding access policy with the same name. For example, the pgsql policy has full access to the pgsql bucket, and so on.

You can also add a lock flag to bucket definitions to enable object locking, preventing accidental deletion of objects in the bucket.


minio_users

Parameter: minio_users, Type: user[], Level: C

List of Silo users to create, default value:

minio_users:
  - { access_key: pgbackrest  ,secret_key: S3User.Backup ,policy: pgsql }
  - { access_key: s3user_meta ,secret_key: S3User.Meta   ,policy: meta  }
  - { access_key: s3user_data ,secret_key: S3User.Data   ,policy: data  }

The default configuration creates three users corresponding to three default buckets:

  • pgbackrest: For PostgreSQL pgBackREST backups, with access to the pgsql bucket.
  • s3user_meta: For accessing the meta bucket.
  • s3user_data: For accessing the data bucket.
Using default passwords is dangerous! Make sure to change these credentials in your deployment!

Tip: ./configure -g will automatically replace these passwords in the configuration template if they appear as defaults.


MINIO_REMOVE

This section contains parameters for the minio_remove role, used by the minio-rm.yml playbook.

minio_safeguard

Parameter: minio_safeguard, Type: bool, Level: G/C/A

Safeguard switch to prevent accidental deletion, default value is false.

When enabled, the minio-rm.yml playbook aborts and refuses to remove the Silo cluster, protecting it against accidental deletion.

It’s recommended to enable this safeguard in production environments to prevent data loss from accidental operations:

minio_safeguard: true   # When enabled, minio-rm.yml will refuse to execute

minio_rm_data

Parameter: minio_rm_data, Type: bool, Level: G/C/A

Remove Silo data and configuration during removal? Default value is true.

When enabled, the minio-rm.yml playbook deletes data directories, /etc/default/silo, the .minio user directory, and /etc/systemd/system/silo.service. Setting it to false preserves data and configuration but does not prevent service deregistration, stopping, or disabling.


minio_rm_pkg

Parameter: minio_rm_pkg, Type: bool, Level: G/C/A

Uninstall Silo packages during removal? Default value is false.

When enabled, the minio-rm.yml playbook uninstalls silo and mcli. This option is disabled by default so the packages remain available for later use.

4 - Playbook

Deploy or remove Silo object-storage clusters with the built-in Ansible playbooks.

The MINIO module provides two built-in playbooks:

  • minio.yml: Install and configure Silo
  • minio-rm.yml: Remove Silo, its configuration, and optionally its data

minio.yml

minio.yml runs with hosts: all, but its pre-tasks skip hosts where minio_cluster is undefined. The role then validates that:

  • minio_cluster is defined and non-empty
  • minio_seq is defined and is a non-negative integer
  • minio_type must equal silo

Thus, minio_cluster is the module-membership gate, while invalid minio_seq or minio_type values fail identity validation explicitly. Do not define minio_cluster in all.vars.

The main task tags are:

  • minio-id: Validate identity and compute actual members, node names, and volume parameters from minio_cluster across the inventory
  • minio_install: Create the minio OS user, install Silo and mcli, and prepare data directories
    • minio_os_user
    • minio_pkg
    • minio_dir
  • minio_config: Render /etc/default/silo, /etc/systemd/system/silo.service, certificates, and DNS
    • minio_conf
    • minio_cert
    • minio_dns
  • minio_launch: Start or restart silo.service
  • minio_register: Write VictoriaMetrics FileSD targets
  • minio_provision: Have the cluster’s first member provision mcli aliases, buckets, and users once

Re-running minio.yml may restart a running object-storage service, but it does not proactively rebuild data. Schedule production runs according to the cluster’s failure budget.


minio-rm.yml

minio-rm.yml uses the same minio_cluster membership gate and identity validation, then runs:

  • minio_safeguard: Accidental-removal protection, default false
  • minio_pause: Pause for 3 seconds so you can abort with Ctrl+C
  • minio_deregister: Remove VictoriaMetrics targets and DNS records
  • minio_svc: Stop and disable the Silo service
  • minio_data: Delete data and configuration according to minio_rm_data
  • minio_pkg: Uninstall Silo and mcli according to minio_rm_pkg
Dangerous Operation

minio_rm_data defaults to true. A full removal run deletes every expanded minio_data directory. Before running it, verify minio_cluster, minio_seq, minio_type: silo, and all disk mount paths. To retire only the service while retaining data, explicitly pass -e minio_rm_data=false.

Both deployment and removal roles default minio_type to silo; other values are rejected. The removal examples still pass it explicitly as part of reviewing the package, service, certificate directory, and data paths; it is not an additional interactive confirmation gate.


Cheatsheet

./minio.yml -l <group>                         # Deploy members with a minio_cluster identity in this limit
./minio.yml -l minio -t minio_install         # Install Silo and mcli; prepare directories
./minio.yml -l minio -t minio_config          # Re-render configuration, certificates, and DNS
./minio.yml -l minio -t minio_launch          # Restart the Silo service
./minio.yml -l minio -t minio_register        # Refresh monitoring targets
./minio.yml -l minio -t minio_provision       # Re-provision aliases, buckets, and users

./minio-rm.yml -l minio -e minio_type=silo                         # Remove Silo services, configuration, and data
./minio-rm.yml -l minio -e minio_type=silo -e minio_rm_data=false  # Remove services while preserving data and configuration
./minio-rm.yml -l minio -e minio_type=silo -e minio_rm_pkg=true    # Also uninstall Silo and mcli

If the configuration group name differs from minio_cluster, note that -l takes an Ansible group or host pattern, not the logical cluster name. Use a limit expression that covers every intended member.


Safeguard

For production clusters, enable accidental-removal protection in cluster variables:

minio_safeguard: true

After carefully verifying the target and backups, explicitly override it when destruction is required:

./minio-rm.yml -l minio -e minio_type=silo -e minio_safeguard=false

Demo

asciicast

5 - Administration

Create, remove, upgrade, expand, shrink, and recover Silo object-storage clusters.

Create Cluster

To create a cluster, define it in the config inventory and run the minio.yml playbook.

minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio, minio_type: silo } }

The configuration above defines an SNSD Single-Node Single-Disk Silo cluster. Create it with:

./minio.yml -l minio  # Install Silo on the minio group

Remove Cluster

To destroy a cluster, run the dedicated minio-rm.yml playbook:

./minio-rm.yml -l minio -e minio_type=silo
./minio-rm.yml -l minio -e minio_type=silo -e minio_rm_data=false
./minio-rm.yml -l minio -e minio_type=silo -e minio_rm_pkg=true

The removal role also defaults minio_type to silo; other values are rejected. The examples still spell it out so the backend, cluster identity, and paths are visible during review.

Architecture Change: Pigsty v3.6+

Starting from Pigsty v3.6, cluster removal has been migrated from minio.yml playbook to the dedicated minio-rm.yml playbook. The old minio_clean task has been deprecated.

The removal playbook attempts these operations in order:

  • Deregisters object-storage targets from VictoriaMetrics monitoring
  • Removes records from the DNS service on INFRA nodes
  • Stops and disables silo.service
  • Deletes data directories and Silo configuration (minio_rm_data, enabled by default)
  • Uninstalls Silo and mcli packages (minio_rm_pkg, disabled by default)

The playbook tolerates errors. Its return status alone does not prove that the service, data, DNS records, and monitoring targets were all handled as intended; inspect each item after a real run.


Expand Cluster

This section uses the MinIO-compatible administration interfaces retained by Silo. Before a production operation, verify the constraints of the exact Silo version and complete a dedicated rehearsal.

Silo cannot directly change the node or disk count of an existing storage pool, but it can expand by adding a new pool.

Assume you have a four-node Silo cluster and want to double capacity by adding a new four-node storage pool.

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 , nodename: minio-1 }
    10.10.10.11: { minio_seq: 2 , nodename: minio-2 }
    10.10.10.12: { minio_seq: 3 , nodename: minio-3 }
    10.10.10.13: { minio_seq: 4 , nodename: minio-4 }
  vars:
    minio_cluster: minio
    minio_type: silo
    minio_data: '/data{1...4}'
    minio_buckets: [ { name: pgsql }, { name: infra }, { name: redis } ]
    minio_users:
      - { access_key: dba , secret_key: S3User.DBA, policy: consoleAdmin }
      - { access_key: pgbackrest , secret_key: S3User.SomeNewPassWord , policy: readwrite }

    # bind a node l2 vip (10.10.10.9) to minio cluster (optional)
    node_cluster: minio
    vip_enabled: true
    vip_vrid: 128
    vip_address: 10.10.10.9
    vip_interface: eth1

    # expose minio service with haproxy on all nodes
    haproxy_services:
      - name: minio                    # [REQUIRED] service name, unique
        port: 9002                     # [REQUIRED] service port, unique
        balance: leastconn             # [OPTIONAL] load balancer algorithm
        options:                       # [OPTIONAL] minio health check
          - option httpchk
          - option http-keep-alive
          - http-check send meth OPTIONS uri /minio/health/live
          - http-check expect status 200
        servers:
          - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

First, modify the Silo cluster definition to add four new nodes, assigning sequence numbers 5 to 8. The key step is to modify the minio_volumes parameter to designate the new four nodes as a new storage pool.

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 , nodename: minio-1 }
    10.10.10.11: { minio_seq: 2 , nodename: minio-2 }
    10.10.10.12: { minio_seq: 3 , nodename: minio-3 }
    10.10.10.13: { minio_seq: 4 , nodename: minio-4 }
    # new nodes
    10.10.10.14: { minio_seq: 5 , nodename: minio-5 }
    10.10.10.15: { minio_seq: 6 , nodename: minio-6 }
    10.10.10.16: { minio_seq: 7 , nodename: minio-7 }
    10.10.10.17: { minio_seq: 8 , nodename: minio-8 }

  vars:
    minio_cluster: minio
    minio_type: silo
    minio_data: '/data{1...4}'
    minio_volumes: 'https://minio-{1...4}.pigsty:9000/data{1...4} https://minio-{5...8}.pigsty:9000/data{1...4}'  # new cluster config
    # ... other configs omitted

Step 2: Add these nodes to Pigsty:

./node.yml -l 10.10.10.14,10.10.10.15,10.10.10.16,10.10.10.17

Step 3: On the new nodes, use the Ansible playbook to install and prepare Silo:

./minio.yml -l 10.10.10.14,10.10.10.15,10.10.10.16,10.10.10.17 -t minio_install

Step 4: On the entire cluster, use the Ansible playbook to reconfigure Silo:

./minio.yml -l minio -t minio_config

This step updates the MINIO_VOLUMES configuration on the existing four nodes

Step 5: Restart the entire Silo cluster at once (do not use a rolling restart):

./minio.yml -l minio -t minio_launch -f 10   # Up to 10 forks; restart all 8 nodes together

Step 6 (optional): If you are using a load balancer, make sure the load balancer configuration is updated. For example, add the new four nodes to the load balancer configuration:

# expose minio service with haproxy on all nodes
haproxy_services:
  - name: minio                    # [REQUIRED] service name, unique
    port: 9002                     # [REQUIRED] service port, unique
    balance: leastconn             # [OPTIONAL] load balancer algorithm
    options:                       # [OPTIONAL] minio health check
      - option httpchk
      - option http-keep-alive
      - http-check send meth OPTIONS uri /minio/health/live
      - http-check expect status 200
    servers:
      - { name: minio-1 ,ip: 10.10.10.10 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-2 ,ip: 10.10.10.11 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-3 ,ip: 10.10.10.12 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-4 ,ip: 10.10.10.13 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

      - { name: minio-5 ,ip: 10.10.10.14 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-6 ,ip: 10.10.10.15 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-7 ,ip: 10.10.10.16 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
      - { name: minio-8 ,ip: 10.10.10.17 ,port: 9000 ,options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

Then, run the haproxy subtask of the node.yml playbook to update the load balancer configuration:

./node.yml -l minio -t haproxy_config,haproxy_reload   # Update and reload load balancer config

If you use L2 VIP for reliable load balancer access, you also need to add new nodes (if any) to the existing NODE VIP group:

./node.yml -l minio -t node_vip  # Refresh cluster L2 VIP configuration

Shrink Cluster

Silo cannot directly reduce the node or disk count of an existing storage pool. To shrink at the pool level, add a new pool, drain the old pool into it, and then retire the old pool.


Upgrade Cluster

First, download the new silo and mcli packages to the local repository on the INFRA node, then rebuild repository metadata with SOW:

./infra.yml -t repo_create

Next, upgrade the Silo server and compatible mcli client:

ansible minio -m package -b -a 'name=silo state=latest'  # Server
ansible minio -m package -b -a 'name=mcli state=latest'  # Compatible client

Finally, have the role restart the complete Silo cluster:

./minio.yml -l minio -t minio_config,minio_launch

A package upgrade and migration from legacy MinIO to Silo are different operations. The former applies to a cluster already running Silo; the latter requires separate data-compatibility validation, backups, a maintenance window, and a rehearsed rollback plan. Do not reuse this upgrade procedure for migration.


Node Failure Recovery

# 1. Remove the failed node from the cluster
bin/node-rm <your_old_node_ip>

# 2. Replace the failed node and keep its original name (if the IP changes, update the Silo cluster definition)
bin/node-add <your_new_node_ip>

# 3. Install and configure Silo on the new node
./minio.yml -l <your_new_node_ip>

# 4. Instruct Silo to heal
mcli admin heal

Disk Failure Recovery

# 1. Unmount the failed disk from the cluster
umount /dev/<your_disk_device>

# 2. Replace the failed disk, format with xfs
mkfs.xfs /dev/sdb -L DRIVE1

# 3. Don't forget to setup fstab for auto-mount
vi /etc/fstab
# LABEL=DRIVE1     /mnt/drive1    xfs     defaults,noatime  0       2

# 4. Remount
mount -a

# 5. Instruct Silo to heal
mcli admin heal

Manage Silo Passwords

minio_secret_key, which defaults to S3User.MinIO, is the Silo root password. It is rendered to /etc/default/silo.

After changing it, refresh configuration and restart the entire cluster:

./minio.yml -l minio -t minio_config,minio_launch,minio_alias -f 30

To change a regular Silo user password, such as pgbackrest, run this on a node that can access Silo:

set +o history
mcli admin user passwd sss pgbackrest <YOUR_NEW_PASSWORD>
set -o history

Then update every consumer of that password. For example, if pgBackRest uses the minio S3-compatible repository preset, refresh its configuration with:

./pgsql.yml -t pgbackrest_config

6 - Monitoring and Alerting

How Pigsty monitors Silo, including its Metrics V3 endpoint, Grafana dashboards, and alert rules.

Administration UI

Silo provides an administration UI through minio_admin_port, which defaults to 9001. Access it directly at https://<node-ip>:9001.

Some configuration templates also expose the administration entry point at m.pigsty. Login credentials come from minio_access_key and minio_secret_key.

HTTPS and Certificate Trust

Object storage uses HTTPS certificates issued by the Pigsty CA by default. Browsers and container clients must trust that CA. Do not substitute disabled certificate verification for a correct trust configuration in production.


Collection Paths

Silo retains the stable job="minio", cls, ins, ip, and instance identity labels and uses flavor="silo":

Backend Metric Path Target and Labels
Silo VictoriaMetrics scrapes https://<instance>:9000/minio/metrics/v3 job=minio, flavor=silo

Each instance’s FileSD target is written to /infra/targets/minio/<minio_cluster>-<minio_seq>.yml.

Silo registers one Metrics V3 root endpoint, which exposes cluster, system, API, and aggregated usage metrics. Pigsty drops samples with a non-empty bucket label and does not register separate per-bucket or replication endpoints, keeping time-series cardinality under control.


Grafana Dashboards

Pigsty provides the compatibility-named MinIO Overview / MinIO Instance dashboards for Silo Metrics V3 data, system logs, and instance state.

minio-overview.jpg


Alert Rules

The current files/victoria/rules/minio.yml defines five alerts for Silo:

Alert Condition Summary Severity
MinioServerDown minio_up < 1 for 1 minute CRIT
MinioNodeOffline Five-minute average offline-node count above 0 for 3 minutes WARN
MinioDiskOffline Five-minute average offline-drive count above 0 for 3 minutes WARN
MinioErasureSetUnhealthy Any erasure set’s overall health below 1 for 1 minute CRIT
MinioClusterCapacityHigh Usable capacity utilization above 90% for 15 minutes WARN

Key expressions use Metrics V3 names:

minio_up < 1

max by (cls) (
  avg_over_time(minio_cluster_health_nodes_offline_count{job="minio"}[5m])
) > 0

max by (cls) (
  avg_over_time(minio_cluster_health_drives_offline_count{job="minio"}[5m])
) > 0

min by (cls) (
  minio_cluster_erasure_set_overall_health{job="minio"}
  or (minio_cluster_erasure_set_overall_write_quorum{job="minio"} * 0)
) < 1

max by (cls) (
  1 - (
    (minio_cluster_health_capacity_usable_free_bytes{job="minio"}
     or (minio_cluster_health_capacity_usable_total_bytes{job="minio"} * 0))
    / minio_cluster_health_capacity_usable_total_bytes{job="minio"}
  )
) > 0.90

7 - Metrics

The Metrics V3 interface, key metrics, and stable labels used by the Pigsty MINIO module to monitor Silo.

The MINIO module collects Silo metrics through /minio/metrics/v3. The metric set varies with server versions and enabled features, so this page documents the stable interfaces used by current dashboards and alerts rather than treating a complete scrape from one version as a permanent contract.


Stable Identity Labels

All object-storage targets use these Pigsty labels:

Label Meaning Example
job Fixed module namespace minio
flavor Actual backend silo
cls minio_cluster identity minio
ins <minio_cluster>-<minio_seq> instance identity minio-1
ip Inventory management address 10.10.10.10
instance Metric target address 10.10.10.10:9000

Queries and recording rules should prefer the stable cls, ins, and ip identity labels.


Silo Metrics V3

Each Silo instance exposes only the V3 root endpoint, /minio/metrics/v3. Current key metrics are:

Category Key Metrics Meaning
Liveness minio_up Pigsty scrape/health state for the instance
Nodes minio_cluster_health_nodes_online_count, minio_cluster_health_nodes_offline_count Online and offline nodes
Drives minio_cluster_health_drives_online_count, minio_cluster_health_drives_offline_count Online and offline drives
Capacity minio_cluster_health_capacity_raw_total_bytes Raw total capacity
Capacity minio_cluster_health_capacity_usable_total_bytes, minio_cluster_health_capacity_usable_free_bytes Usable total and free capacity
Objects minio_cluster_usage_objects_count, minio_cluster_usage_objects_total_bytes Object count and used bytes
Buckets minio_cluster_usage_objects_buckets_count Aggregated bucket count
Erasure coding minio_cluster_erasure_set_overall_health, minio_cluster_erasure_set_overall_write_quorum Erasure-set health and write quorum
API minio_api_requests_total, minio_api_requests_errors_total, minio_api_requests_4xx_errors_total API requests and errors
API minio_api_requests_inflight_total, minio_api_requests_incoming_total In-flight and incoming requests
Traffic minio_api_requests_traffic_received_bytes, minio_api_requests_traffic_sent_bytes Received and sent bytes
Latency minio_api_requests_ttfb_seconds_distribution Time-to-first-byte distribution
Process minio_system_process_cpu_total_seconds, minio_system_process_resident_memory_bytes Process CPU and resident memory
System minio_system_drive_free_bytes, minio_system_drive_used_bytes, minio_system_drive_health Per-drive capacity and health
Audit minio_audit_total_messages Audit-message count

Pigsty drops samples whose bucket label is non-empty at scrape time and does not register dedicated per-bucket or replication endpoints. This is an intentional cardinality-control policy. If per-bucket metrics are required, evaluate the time-series volume before adding a custom scrape job.

8 - FAQ

Frequently asked questions about the Pigsty MINIO object storage module

Which backend does the MINIO module deploy by default?

In v4.5.0, the current source deploys Silo—and only Silo. The only valid value for minio_type is silo. MINIO remains the compatibility module name; it does not mean the MinIO server is running.

  • Explicitly set minio_type: silo for new clusters.
  • Both minio_type: minio and minio_type: rustfs fail during identity validation.
  • External MinIO, RustFS, or other S3 services can still serve as pgBackRest repositories, but the current MINIO role does not manage them.
  • Before upgrading a MinIO cluster managed by an older release, validate the MinIO-to-Silo data compatibility, backup, and rollback procedure.

Why does the Pigsty repository still carry MinIO or RustFS packages?

Upstream MinIO switched to source-only distribution on 2025-10-15, marked the repository as maintenance mode on 2025-12-03, and archived it on 2026-04-25. Here, “source-only distribution” means that new prebuilt community binaries stopped being published—not merely RPM and DEB packages.

Pigsty therefore previously maintained its own MinIO fork and packages. MinIO CVE-2025-62506 affects releases before RELEASE.2025-10-15T17-29-55Z and is fixed in that release; both Pigsty’s later MinIO fork and the current Silo code include the fix.

The Pigsty Infra repository still carries MinIO/RustFS RPM and DEB packages plus their build scripts, but repository availability does not mean that the v4.5 MINIO module supports those backends. The current role accepts only Silo; other services must be deployed and maintained separately.


Why is HTTPS enabled for object storage by default?

Pigsty’s default pgBackRest minio repository configuration uses HTTPS and verifies the certificate through /etc/pki/ca.crt to protect backup traffic. pgBackRest does not categorically forbid HTTP. If you explicitly choose HTTP, you must update the TLS options in pgbackrest_repo as well as disable minio_https; changing only the server-side switch is insufficient.


Getting an invalid certificate error when accessing Silo from containers?

By default, the object-storage server certificate is issued by Pigsty’s private CA. It is not a self-signed server certificate, but container images usually do not trust this private CA, so clients such as mcli, rclone, and AWS CLI report an invalid certificate chain.

For example, for a Node.js application, mount the Pigsty CA certificate into the container and specify its path through NODE_EXTRA_CA_CERTS:

    environment:
      NODE_EXTRA_CA_CERTS: /etc/pki/ca.crt
    volumes:
      - /etc/pki/ca.crt:/etc/pki/ca.crt:ro

If Silo is not used as a pgBackRest backup repository, you can disable HTTPS and use HTTP instead, but you should also assess the risk of cleartext transport.


Can a Silo data path be a regular directory?

minio_data takes a directory path, not a raw disk device. /data/minio may be a regular subdirectory, but in multi-node or multi-drive deployments its backing storage must be an independent, persistent, non-root filesystem.

  • If /data is mounted from a separate local disk, cloud volume, partition, or LVM logical volume, /data/minio is valid.
  • If /data/minio is only a directory created under the root filesystem, distributed Silo marks it as a root drive and rejects it with drive is part of root drive, will not be used.
  • Every path in a single-node multi-drive deployment should map to a separate filesystem. Multiple directories on one drive do not emulate multiple drives.
  • Only single-node single-disk may use a regular directory directly on the root filesystem, and only for development, testing, or non-critical use.

Inspect the backing mounts with:

findmnt -T /
findmnt -T /data/minio

See Configuration: Storage Paths and Mounts for details and Multi-Node Single-Disk for the three-node topology.


How do I add new members to an existing Silo cluster?

Plan Silo cluster capacity before deployment because adding a storage pool requires a global restart.

Scale the cluster by adding a group of server nodes as a new storage pool.

You cannot directly change the node or disk count of an existing storage pool; expansion requires adding a new pool.

For the procedure, see Pigsty’s Expand Cluster guide and the upstream Expand MinIO Deployment reference for the compatible interface retained by Silo.


How do I remove a Silo cluster?

Starting with Pigsty v3.6, cluster removal uses the dedicated minio-rm.yml playbook:

./minio-rm.yml -l minio -e minio_type=silo
./minio-rm.yml -l minio -e minio_type=silo -e minio_rm_data=false

The removal role also defaults minio_type to silo; other values are rejected. The examples still spell it out so the operator can review it together with cluster identity and paths before deletion.

minio_rm_data defaults to true, and the removal role tolerates some cleanup errors. Before a real run, verify the exact -l target and a recent backup. Afterwards, inspect the service, data directories, DNS records, and monitoring targets; the playbook’s return status alone does not prove that cleanup completed.

If you have enabled minio_safeguard protection, you need to explicitly override it to perform removal:

./minio-rm.yml -l minio -e minio_type=silo -e minio_safeguard=false

What’s the difference between mcli and mc commands?

Pigsty ships the compatible MinIO client under the mcli command and package name instead of upstream’s mc, avoiding a name collision with the Midnight Commander file manager.

mcli is Pigsty’s delivery name for the compatible client and retains the mc CLI, although the exact version may change with Pigsty packaging. See the MinIO Client documentation for the command reference.


How do I monitor Silo cluster status?

Pigsty provides out-of-the-box monitoring for Silo. Dashboard and metric names retain MinIO-compatible naming:

  • Grafana Dashboards: MinIO Overview and MinIO Instance
  • Alerting Rules: MinIO-compatible server-down, node-offline, and disk-offline alerts
  • Silo Built-in Console: Access via https://<minio-ip>:9001

For details, see Monitoring.