How to Deploy MinIO – Object Storage Server

MinIO is a high-performance, open-source object storage server that is fully compatible with the Amazon S3 API. It is designed for modern cloud-native workloads, making it suitable for backups, media storage, data lakes, analytics, and application storage.
This article demonstrates how to deploy MinIO on Ubuntu 24.04 using Docker Compose and secure both the API and the Console using a Traefik reverse proxy.
Prerequisites
Before you begin:
- Access an Ubuntu 24.04 server as a non-root user with sudo privileges.
- Install Docker and Docker Compose.
- Configure two domain names pointing to your server's public IP address:
console.example.com(For the Web UI).s3.example.com(For the S3 API endpoint).
Set Up the Directory Structure and Environment Variables
MinIO stores object data on disk and relies on environment variables for credentials, domains, and TLS configuration. This section prepares the required directory structure for persistent storage and defines the environment variables used by Docker Compose and Traefik during deployment.
Create the project folders.
console$ mkdir -p ~/minio/{data,letsencrypt}
data- Stores the actual object data.letsencrypt- Stores Traefik ACME certificates.
Navigate to the root MinIO directory.
console$ cd ~/minio
Create an
.envfile to store your credentials and domain configurations.console$ nano .env
Add the following values:
iniMINIO_ROOT_USER=admin MINIO_ROOT_PASSWORD=STRONG_PASSWORD DOMAIN_CONSOLE=console.example.com DOMAIN_API=s3.example.com LETSENCRYPT_EMAIL=admin@example.com
Replace the placeholders with your own values:
STRONG_PASSWORD– A secure password for the MinIO admin user.console.example.com– Domain for the MinIO web console.s3.example.com– Domain for the MinIO S3 API endpoint.admin@example.com– Email address for Let’s Encrypt notifications.
Save and close the file.
Deploy with Docker Compose
This section deploys the MinIO server behind Traefik. The configuration exposes two services: the Console (Web UI) on port 9001 and the API (S3 access) on port 9000.
Add your user account to the docker user group.
console$ sudo usermod -aG docker $USER
Apply the new group membership.
console$ newgrp docker
Create the Docker Compose manifest file.
console$ nano docker-compose.yml
Add the following contents:
yamlservices: traefik: image: traefik:latest container_name: traefik restart: unless-stopped environment: DOCKER_API_VERSION: "1.44" command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - "--certificatesresolvers.le.acme.httpchallenge=true" - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web" - "--certificatesresolvers.le.acme.email=${LETSENCRYPT_EMAIL}" - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./letsencrypt:/letsencrypt minio: image: minio/minio:latest container_name: minio restart: unless-stopped command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} MINIO_BROWSER_REDIRECT_URL: https://${DOMAIN_CONSOLE} volumes: - ./data:/data healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 labels: - "traefik.enable=true" # Router 1: The S3 API (Port 9000) - "traefik.http.routers.minio-api.rule=Host(`${DOMAIN_API}`)" - "traefik.http.routers.minio-api.entrypoints=websecure" - "traefik.http.routers.minio-api.tls=true" - "traefik.http.routers.minio-api.tls.certresolver=le" - "traefik.http.routers.minio-api.service=minio-api-svc" - "traefik.http.services.minio-api-svc.loadbalancer.server.port=9000" # Router 2: The Web Console (Port 9001) - "traefik.http.routers.minio-console.rule=Host(`${DOMAIN_CONSOLE}`)" - "traefik.http.routers.minio-console.entrypoints=websecure" - "traefik.http.routers.minio-console.tls=true" - "traefik.http.routers.minio-console.tls.certresolver=le" - "traefik.http.routers.minio-console.service=minio-console-svc" - "traefik.http.services.minio-console-svc.loadbalancer.server.port=9001"
Save and close the file.
This Docker Compose configuration deploys MinIO and exposes it securely over HTTPS using Traefik. The setup separates MinIO’s S3 API and web console onto different domains while keeping all TLS management centralized in Traefik.
minio service
- Runs the official
minio/minioimage, providing high-performance, S3-compatible object storage. - Starts MinIO in server mode, storing all objects in the
/datadirectory, which is persistently mounted from./dataon the host. - Exposes two internal ports:
- 9000 – MinIO S3 API endpoint (used by applications, backups, and clients).
- 9001 – MinIO web console for administration and monitoring.
- Uses environment variables to:
- Define the root access credentials (
MINIO_ROOT_USER,MINIO_ROOT_PASSWORD). - Set
MINIO_BROWSER_REDIRECT_URLso that the web console redirects correctly through Traefik over HTTPS.
- Define the root access credentials (
- Includes a health check that verifies MinIO’s internal health endpoint, allowing Docker to track service availability.
Traefik integration (via labels)
- Traefik discovers MinIO automatically using Docker labels.
- Two separate HTTPS routers are defined:
- MinIO API router
- Routes traffic for
${DOMAIN_API}to MinIO’s S3 API on port 9000. - Intended for programmatic access (SDKs, CLI tools, backups).
- Routes traffic for
- MinIO Console router
- Routes traffic for
${DOMAIN_CONSOLE}to the MinIO web console on port 9001. - Intended for browser-based administration.
- Routes traffic for
- MinIO API router
- Both routers:
- Listen on the
websecureentrypoint. - Use Let’s Encrypt (
le) to automatically obtain and renew TLS certificates.
- Listen on the
- Each router maps to a dedicated Traefik service to ensure traffic is forwarded to the correct internal port.
traefik service
- Acts as the reverse proxy and TLS terminator for MinIO.
- Listens on ports 80 and 443 on the host.
- Automatically redirects HTTP traffic to HTTPS.
- Stores Let’s Encrypt ACME certificates in the
./letsencryptdirectory. - Uses the Docker socket (read-only) to discover services and apply routing rules dynamically.
- Runs the official
Start the services.
console$ docker compose up -d
Verify the containers are running.
console$ docker compose ps
For more information on managing a Docker Compose stack, see the How To Use Docker Compose article.Note
Access MinIO
Open your web browser and navigate to your Console domain
https://console.example.com.Log in using the
MINIO_ROOT_USERandMINIO_ROOT_PASSWORDyou configured in the.envfile.On your first login, a License Disclaimer window appears. Click Acknowledge to accept the terms and proceed to the dashboard.

Upon successful login, the Buckets dashboard loads. You can now create your first storage bucket.
To test the API connection, you can use any S3-compatible client (like s3cmd) using the following details:
- Endpoint:
https://s3.example.com - Access Key: Value of
MINIO_ROOT_USER - Secret Key: Value of
MINIO_ROOT_PASSWORD
- Endpoint:
Conclusion
By following this article, you successfully deployed the MinIO object storage server on Ubuntu 24.04. You configured Traefik to securely route traffic to both the S3 API and the web administration console. Your server is now ready to store data for applications, backups, or AI workloads. For more information, refer to the MinIO Documentation.