KB
Object Storage & S3

Deploy Single Node MinIO Server with Nginx Reverse Proxy (Ubuntu 24.04 LTS)

3 min read511 words15 code blocks

At a glance#

  • Purpose: Deploy a single-node MinIO server behind an nginx reverse proxy with TLS termination.
  • Applies to: MinIO on Ubuntu 24.04 LTS.
  • Risk: Medium - new service deployment.
  • Time: About 1 hour.

1. OS Installation#

  • Install Ubuntu Server 24.04 LTS minimal
  • Single / partition (65 GB+) or whatever the storage is
  • Set hostname:
bash
sudo hostnamectl set-hostname minio

2. System Update & Tools#

bash
sudo apt update && sudo apt upgrade -y
sudo apt install ufw curl wget openssl nginx -y

3. Firewall Setup#

bash
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

4. MinIO User & Data Directory#

bash
sudo useradd -r -m -U -d /srv/minio -s /usr/sbin/nologin minio-user
sudo mkdir -p /srv/minio-data
sudo chown minio-user:minio-user /srv/minio-data

5. Install MinIO Server Binary#

bash
wget https://dl.min.io/server/minio/release/linux-amd64/minio
sudo mv minio /usr/local/bin/
sudo chmod +x /usr/local/bin/minio

6. Environment File#

Generate strong creds:

bash
ACCESS_KEY="$(openssl rand -hex 6)"        # >=3 chars
SECRET_KEY="$(openssl rand -base64 24 | tr -d '/+=\n')"  # >=8 chars

Create /etc/default/minio:

bash
sudo tee /etc/default/minio >/dev/null <<EOF
MINIO_ROOT_USER=${ACCESS_KEY}
MINIO_ROOT_PASSWORD=${SECRET_KEY}
MINIO_VOLUMES="/srv/minio-data"
MINIO_OPTS="--address 127.0.0.1:9000 --console-address 127.0.0.1:9001"
MINIO_SERVER_URL=https://s3.example.com
MINIO_BROWSER_REDIRECT_URL=https://s3.example.com/minio/ui/
EOF

sudo chmod 600 /etc/default/minio
sudo chown root:root /etc/default/minio

7. Systemd Service#

/etc/systemd/system/minio.service:

text
[Unit]
Description=MinIO
Documentation=https://min.io/docs/minio/linux/index.html
Wants=network-online.target
After=network-online.target

[Service]
User=minio-user
Group=minio-user
EnvironmentFile=/etc/default/minio
ExecStart=/usr/local/bin/minio server $MINIO_VOLUMES $MINIO_OPTS
Restart=always
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
bash
sudo systemctl daemon-reload
sudo systemctl enable --now minio

8. Nginx Reverse Proxy with TLS#

  • Place cert & key in /etc/nginx/ssl/:
bash
sudo mkdir -p /etc/nginx/ssl
sudo cp s3_leaf.crt /etc/nginx/ssl/
sudo cp ca_bundle.crt /etc/nginx/ssl/
sudo cp s3.key /etc/nginx/ssl/
sudo bash -c 'cat /etc/nginx/ssl/s3_leaf.crt /etc/nginx/ssl/ca_bundle.crt > /etc/nginx/ssl/s3.fullchain.crt'
sudo chmod 600 /etc/nginx/ssl/s3.key
  • Create /etc/nginx/sites-available/minio.conf:
text
server {
    listen 80;
    listen [::]:80;
    server_name s3.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name s3.example.com;

    ssl_certificate     /etc/nginx/ssl/s3.fullchain.crt;
    ssl_certificate_key /etc/nginx/ssl/s3.key;
    ssl_trusted_certificate /etc/nginx/ssl/s3.fullchain.crt;

    ignore_invalid_headers off;
    client_max_body_size 0;
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        chunked_transfer_encoding off;
        proxy_pass http://127.0.0.1:9000;
    }

    location /minio/ui/ {
        rewrite ^/minio/ui/(.*) /$1 break;
        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-NginX-Proxy     true;
        real_ip_header X-Real-IP;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        chunked_transfer_encoding off;
        proxy_pass http://127.0.0.1:9001;
    }
}

Enable & reload:

bash
sudo ln -s /etc/nginx/sites-available/minio.conf /etc/nginx/sites-enabled/minio.conf
sudo nginx -t && sudo systemctl reload nginx

9. MinIO Client (mc)#

bash
wget https://dl.min.io/client/mc/release/linux-amd64/mc
sudo mv mc /usr/local/bin/
sudo chmod +x /usr/local/bin/mc

mc alias set prod https://s3.example.com $ACCESS_KEY $SECRET_KEY
mc admin info prod

10. Create Bucket & App User#

bash
mc mb prod/mybucket

cat > /tmp/mybucket-rw.json <<'JSON'
{
  "Version":"2012-10-17",
  "Statement":[
    {"Effect":"Allow","Action":["s3:ListBucket"],"Resource":["arn:aws:s3:::mybucket"]},
    {"Effect":"Allow","Action":["s3:GetObject","s3:PutObject","s3:DeleteObject"],"Resource":["arn:aws:s3:::mybucket/*"]}
  ]
}
JSON

mc admin policy create prod mybucket-rw /tmp/mybucket-rw.json

APP_USER="app_user"
APP_PASS="$(openssl rand -base64 30 | tr -d '/+=\n')"
mc admin user add prod "$APP_USER" "$APP_PASS"
mc admin policy attach prod mybucket-rw --user "$APP_USER"

11. Health Checks#

bash
curl -Ik https://s3.example.com/minio/health/ready
curl -s http://127.0.0.1:9000/minio/health/ready && echo