How to Set Up Self-Hosted S3-Compatible Object Storage with MinIO

MinIO is a high-performance, self-hosted object storage server compatible with the S3 API — letting you run your own object storage on a VPS instead of paying for third-party storage, while keeping compatibility with S3-compatible tools and libraries.

Why Self-Host Object Storage

  • Full control over data location and retention
  • Potentially lower cost at scale compared to hosted providers
  • S3-compatible API means most existing tools/SDKs work without modification

Prerequisites

  • A VPS with adequate storage for your needs
  • Docker Engine installed

Step 1 — Run MinIO

docker run -d \
  --name minio \
  --restart unless-stopped \
  -p 9000:9000 \
  -p 9001:9001 \
  -e MINIO_ROOT_USER=admin \
  -e MINIO_ROOT_PASSWORD=CHANGE_ME_STRONG_PASSWORD \
  -v minio_data:/data \
  minio/minio server /data --console-address ":9001"

Port 9000 is the S3 API endpoint, port 9001 is the web console.

Step 2 — Allow the Required Ports

sudo ufw allow from YOUR_TRUSTED_IP to any port 9001
sudo ufw allow 9000/tcp

Restrict the console (9001) to trusted IPs; the API port (9000) needs broader access if your applications connect from elsewhere.

Step 3 — Access the Web Console

http://YOUR_SERVER_IP:9001

Log in with the root credentials set above.

Step 4 — Create a Bucket

In the console: Buckets → Create Bucket, name it (e.g. myapp-uploads).

Step 5 — Create an Access Key for Applications

Under Access Keys → Create access key — use this for application connections rather than the root credentials.

Step 6 — Add HTTPS

Route both the API and console through Nginx Proxy Manager (see How to Install Nginx Proxy Manager with Docker) with valid SSL — critical since credentials and data transfer over this connection.

Step 7 — Test with the AWS CLI

aws configure --profile minio
aws s3 ls --profile minio --endpoint-url https://storage.yourdomain.com

Uploading a Test File

aws s3 cp test.txt s3://myapp-uploads/ --profile minio --endpoint-url https://storage.yourdomain.com

Setting Bucket Policies

Configure public/private access per bucket through the console under bucket settings — keep buckets private by default, only making specific buckets/paths public if genuinely needed.

Setting Up Lifecycle Rules

In the console, configure automatic expiration/deletion rules per bucket — useful for temporary uploads or enforcing retention policies without manual cleanup scripts.

Backing Up MinIO Data

docker run --rm -v minio_minio_data:/data -v $(pwd):/backup alpine tar czf /backup/minio-backup.tar.gz /data

Alternatively, use MinIO's own replication features to sync to a second MinIO instance for redundancy.

Common Errors

"Access Denied" — verify you're using an access key with appropriate bucket permissions, not attempting an operation the key isn't authorized for.

Slow uploads/downloads — check your VPS's disk I/O performance and network bandwidth; object storage performance is directly tied to underlying disk speed.

Best Practices

  • Never use root credentials for application connections — create scoped access keys
  • Always run behind HTTPS
  • Keep buckets private by default, exposing only what's genuinely needed publicly

Continue Reading

Browse more articles in Object Storage, Messaging & APIs.

  • minio, self hosted s3, object storage, s3 compatible storage
  • 35 Users Found This Useful
Was this answer helpful?

Related Articles

How to Use Object Storage for Application File Uploads

Storing user-uploaded files directly on your application server's disk creates scaling and...

How to Install and Configure RabbitMQ on a VPS

RabbitMQ is a widely-used, robust message broker — enabling applications to communicate...

How to Install and Configure Redis as a Message Queue

Redis, primarily known as a cache, also works well as a lightweight message queue for simpler use...

How to Build and Secure a REST API on a VPS

Your framework handles routes and business logic; the server around it decides whether the API is...

How to Design and Secure Webhook Endpoints

Webhooks let external services notify your application of events in real time. Since they accept...