
September 10, 2026
11 min read
By Kokil Thapa | Last reviewed: September 2026
Your Laravel app stores PDFs on local disk. Traffic grows. Backups balloon. A restore takes hours. MinIO: S3-Compatible Object Storage solves this without rewriting upload code—you point the same S3 SDK calls at a self-hosted endpoint. I've used this pattern on production enterprise applications where clients need document retention without AWS bills. This guide covers architecture, Ubuntu install, Laravel wiring, and production hardening.
What Is MinIO S3-Compatible Object Storage?
MinIO is an open-source object store built for cloud-native workloads. It stores files as objects inside buckets—the same mental model as Amazon S3. Your application uses path-style or virtual-host URLs. It sends PUT, GET, DELETE, and LIST requests. MinIO responds with S3-compatible XML or JSON.
Object storage differs from block storage (EBS, iSCSI) and file storage (NFS, SMB). Objects are immutable blobs with metadata. You do not mount them as a filesystem for random writes. That trade-off buys you horizontal scale and cheap bulk retention.
On legal-tech portals I've shipped—client document uploads, notary scans, attestation PDFs—object storage keeps the web server stateless. Files live on a dedicated tier. You scale app servers independently. See our Mijar Law Associates portfolio case for a document-heavy workflow example.
MinIO implements core S3 operations: bucket lifecycle rules, versioning, server-side encryption, and IAM-style policies. It does not replicate every AWS edge case. Glacier tiers and some obscure API calls may differ. For Laravel file uploads, backup tools, and static asset offloading, parity is usually complete enough to swap endpoints.
If you want a deeper self-hosting walkthrough, read our companion post on MinIO self-hosted S3 storage. For AWS-native setups, see AWS S3 for Laravel file storage.
How Do You Install MinIO on Ubuntu for S3-Compatible Storage?
A single-node MinIO install on Ubuntu 22.04 or 24.04 takes under ten minutes. You need a dedicated data directory on fast storage. SSD or NVMe is strongly preferred for metadata latency.
Download and create a system user
Run these commands as root or with sudo on a fresh Ubuntu server with at least two CPU cores and 4 GB RAM for light workloads.
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
sudo mv minio /usr/local/bin/
sudo useradd -r minio-user -s /sbin/nologin
sudo mkdir -p /mnt/minio-data
sudo chown minio-user:minio-user /mnt/minio-data Configure environment and systemd service
Create /etc/default/minio with your root credentials and data path. Never commit these values to Git.
MINIO_ROOT_USER="minioadmin"
MINIO_ROOT_PASSWORD="ChangeThisToALongRandomSecret"
MINIO_VOLUMES="/mnt/minio-data"
MINIO_OPTS="--console-address :9001" Install the systemd unit at /etc/systemd/system/minio.service:
[Unit]
Description=MinIO S3-Compatible Object Storage
After=network-online.target
Wants=network-online.target
[Service]
User=minio-user
Group=minio-user
EnvironmentFile=/etc/default/minio
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
Restart=always
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now minio
sudo systemctl status minio Create your first bucket
Install the MinIO client mc and alias your server:
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc && sudo mv mc /usr/local/bin/
mc alias set local https://minio.example.com minioadmin 'ChangeThisToALongRandomSecret'
mc mb local/app-uploads
mc anonymous set none local/app-uploads Put Nginx or Apache in front with TLS. Terminate HTTPS on the reverse proxy. Forward port 9000 for the S3 API and 9001 for the console. Our Linux system administration service covers hardened production configs for Nepal-hosted VPS and dedicated servers.
How Does MinIO Compare to AWS S3 and Other Object Storage?
Choosing storage is a cost, control, and compliance decision—not a performance contest on day one. MinIO wins when you need S3 API compatibility on hardware you already own or on a budget VPS in Kathmandu.
| Criteria | MinIO (self-hosted) | AWS S3 | Cloudflare R2 |
|---|---|---|---|
| S3 API compatibility | High for core ops | Native reference | High, no egress fees |
| Monthly cost at 500 GB | Server only (~Rs 3,000–8,000 VPS) | Storage + requests + egress | Flat per-GB, zero egress |
| Data residency control | Full—you pick the disk | Region-bound | Cloudflare edge |
| Ops burden | You patch, backup, monitor | Managed by AWS | Managed by Cloudflare |
| Best fit | On-prem, dev/staging, Nepal VPS | Global scale, full AWS stack | Public assets, CDN-heavy sites |
For a full cost breakdown between cloud providers, read Cloudflare R2 vs AWS S3 cost breakdown. Ceph and GlusterFS solve different problems—block and distributed file layers—whereas MinIO focuses purely on object APIs. See Ceph storage fundamentals if you need unified block, file, and object in one cluster.
A pattern I use often: MinIO on a staging VPS mirrors production S3 behaviour. Developers test uploads locally against MinIO. Production points at AWS S3 or R2 with identical Flysystem config. Only the endpoint and credentials change.
How Do You Connect Laravel to MinIO S3-Compatible Object Storage?
Laravel 12 and 13 ship with Flysystem v3 and an S3 adapter. You do not need MinIO-specific packages. Set the disk driver to s3. Point endpoint at your MinIO URL. Set use_path_style_endpoint to true—MinIO requires path-style addressing on single-node setups.
Configure filesystems.php
'disks' => [
'minio' => [
'driver' => 's3',
'key' => env('MINIO_ACCESS_KEY'),
'secret' => env('MINIO_SECRET_KEY'),
'region' => env('MINIO_REGION', 'us-east-1'),
'bucket' => env('MINIO_BUCKET'),
'url' => env('MINIO_URL'),
'endpoint' => env('MINIO_ENDPOINT'),
'use_path_style_endpoint' => true,
'throw' => true,
],
], Add matching entries to your .env file:
MINIO_ACCESS_KEY=your-access-key
MINIO_SECRET_KEY=your-secret-key
MINIO_BUCKET=app-uploads
MINIO_ENDPOINT=https://minio.example.com
MINIO_URL=https://minio.example.com/app-uploads
MINIO_REGION=us-east-1
FILESYSTEM_DISK=minio Install the AWS SDK if it is not already present:
composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies Upload and retrieve files
Use Laravel's Storage facade exactly as you would with AWS:
use Illuminate\Support\Facades\Storage;
Storage::disk('minio')->put('contracts/agreement.pdf', $request->file('document'));
$url = Storage::disk('minio')->temporaryUrl(
'contracts/agreement.pdf',
now()->addMinutes(15)
); For a broader comparison of local, S3, and R2 disks, see Laravel file uploads with S3, R2, and local storage. On booking platforms like Adventure Third Pole Trek, itinerary PDFs and voucher images benefit from off-server storage that survives app redeploys.
Official Laravel filesystem documentation covers driver options and testing fakes. The MinIO docs describe bucket policies and the mc CLI in detail—both are worth bookmarking (Laravel 12 filesystem docs, MinIO Linux documentation).
What Are the Best Practices for MinIO Production Deployments?
A MinIO node that holds client documents is production infrastructure. Treat it like a database server. Backups, monitoring, and access control are not optional extras.
- Use erasure coding across four or more drives. A single directory on one disk works for dev. Production needs parity shards so one drive failure does not lose data.
- Rotate credentials away from MINIO_ROOT_USER defaults. Create scoped service accounts per application with bucket-level IAM policies.
- Enable versioning on buckets that store legal or financial documents. Accidental deletes become recoverable.
- Mirror buckets off-site nightly. Use
mc mirror, restic, or rclone to a second MinIO cluster or AWS S3. Our guide on offsite backups to S3 or R2 with restic applies directly. - Monitor disk usage and API error rates. A full disk returns 507 errors that break uploads silently in poorly handled code paths.
- Keep the MinIO binary updated. Subscribe to release notes. Schedule maintenance windows like any other server patch cycle.
For automated backup pipelines triggered from cron or GitLab CI, read automate off-site backups to S3. If you run the full stack on EC2, our Laravel on AWS EC2 with RDS and S3 post shows how object storage fits a cloud architecture—you can swap S3 for MinIO on a secondary VPS to cut storage line items.
Encryption at rest is available via KMS integrations or automatic SSE-S3 on newer MinIO releases. For compliance-sensitive legal portals, encrypt before upload in the application layer as well. Defense in depth beats a single toggle.
When sizing hardware, plan for 20–30% free space headroom. Object storage performance degrades sharply above 85% capacity. On a Rs 5,000/month VPS (~USD 37), you can run MinIO for a small law-firm portal's document archive if traffic stays moderate. Heavy video workloads need dedicated nodes.
For data-lake analytics workloads—CSV exports, log aggregation—MinIO also works as an S3 landing zone. See build a data lake on S3 for pipeline patterns that translate directly to MinIO endpoints. The AWS S3 API reference remains the canonical contract for supported operations (Amazon S3 API reference).
If you need help auditing an existing upload pipeline or migrating local storage to object storage, our support and maintenance team handles migrations with zero-downtime cutover plans. You can also validate encoded payloads during integration tests with our Base64 encoder and decoder tool.
Key Takeaways
- MinIO exposes the S3 REST API on your hardware—Laravel, restic, rclone, and Terraform S3 backends work with endpoint changes only.
- Install on Ubuntu via binary + systemd, terminate TLS at Nginx, and never expose port 9000 without authentication.
- Set
use_path_style_endpoint => truein Laravel's S3 disk config when pointing Flysystem at MinIO. - Use erasure coding on four or more drives and nightly
mc mirrorjobs for production-grade durability. - MinIO beats AWS S3 on cost and data residency for Nepal VPS deployments; AWS wins on zero-ops global scale.
- Treat bucket IAM policies, versioning, and disk monitoring as mandatory—not afterthoughts—for document-heavy apps.
People Also Ask
Is MinIO really compatible with the Amazon S3 API?
Yes, for the operations most web apps use daily—bucket CRUD, object PUT/GET/DELETE, presigned URLs, lifecycle rules, and versioning. Edge cases like Glacier transitions or obscure ListObjectsV2 parameters may differ. Test your specific SDK calls in staging before cutover.
Can MinIO run on a single VPS with one disk?
It can, and that is fine for development or low-stakes staging. Production workloads should use at least four drives with erasure coding so a single disk failure does not destroy data. A one-disk setup has no redundancy.
Does Laravel need a special MinIO package?
No. Laravel's built-in s3 Flysystem driver works with MinIO when you set a custom endpoint and enable path-style URLs. Install league/flysystem-aws-s3-v3 and configure credentials in .env.
How do you back up MinIO buckets?
Use the mc mirror command to replicate buckets to a second MinIO cluster, AWS S3, or Cloudflare R2. Tools like restic and rclone also speak S3 and therefore work against MinIO endpoints with no code changes.
Deploy MinIO S3-Compatible Object Storage With Confidence
You now have a complete path from Ubuntu install to Laravel integration. MinIO: S3-Compatible Object Storage gives you vendor-neutral object APIs on infrastructure you control—ideal for Nepal-hosted legal portals, eCommerce media, and staging environments that must mirror production S3 behaviour without the AWS bill.
Start with a staging bucket this week. Wire your Laravel disk config. Run one backup mirror job. If you want a production review of your storage architecture, contact us for a consultation or explore more guides on the Kokil Thapa blog and homepage.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

