How to deploy a self-hold object storage service

In my view of point, object storage is an useful and flat storage tool, which means you do not need to take care about relationship between files, all of them are in same lever. So this is convenient for storage multimedia files. It can storage millions of files as long as your server is powerful enough. Well, let’s start it.

How to install Minio

At first, I just download binary file and run it in background using screen, then I learned how to install with deb file and run with systemd, a more elegant way.

Basic installation

Log into your server as root.

1
2
3
wget https://dl.min.io/server/minio/release/linux-amd64/minio_20240704142545.0.0_amd64.deb # the file url maybe changed, so you'd better get the latest one in https://min.io/download?license=agpl&platform=linux
dpkg -i minio_20240704142545.0.0_amd64.deb
vim /usr/lib/systemd/system/minio.service # systemd checks the /etc/systemd/... path before checking the /usr/lib/systemd/... path and uses the first file it finds. To avoid conflicting or unexpected configuration options, check that the file only exists at the /usr/lib/systemd/system/minio.service path.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[Unit]
Description=MinIO
Documentation=https://min.io/docs/minio/linux/index.html
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio

[Service]
WorkingDirectory=/usr/local

User=minio-user
Group=minio-user
ProtectProc=invisible

EnvironmentFile=-/etc/default/minio
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES

# MinIO RELEASE.2023-05-04T21-44-30Z adds support for Type=notify (https://www.freedesktop.org/software/systemd/man/systemd.service.html#Type=)
# This may improve systemctl setups where other services use `After=minio.server`
# Uncomment the line to enable the functionality
# Type=notify

# Let systemd restart this service always
Restart=always

# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536

# Specifies the maximum number of threads this process can create
TasksMax=infinity

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target

# Built for ${project.name}-${project.version} (${project.name})
1
2
3
4
adduser minio-user
mkdir /mnt/minio_data
chown minio-user:minio-user /mnt/minio_data
vim /etc/default/minio
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# MINIO_ROOT_USER and MINIO_ROOT_PASSWORD sets the root account for the MinIO server.
# This user has unrestricted permissions to perform S3 and administrative API operations on any resource in the deployment.
# Omit to use the default values 'minioadmin:minioadmin'.
# MinIO recommends setting non-default values as a best practice, regardless of environment

MINIO_ROOT_USER=username # replace this with yours
MINIO_ROOT_PASSWORD=password # replace this with yours

# MINIO_VOLUMES sets the storage volume or path to use for the MinIO server.

MINIO_VOLUMES="/mnt/minio_data"

# MINIO_OPTS sets any additional commandline options to pass to the MinIO server.
# For example, `--console-address :9001` sets the MinIO Console listen port
MINIO_OPTS="--console-address :9001"
1
2
sudo systemctl enable minio.service
service minio start

Use Apache2 as web server

Log into your server as root.

1
2
apt install apache2
vim /etc/apache2/sites-available/minio.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<VirtualHost *:80>
ServerName your.domain

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

<VirtualHost *:443>
ServerName your.domain

# SSL configuration
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/your.domain/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/your.domain/privkey.pem
# Maybe you need to comment these before you generate a ssl certificate

# Enable SSL Proxy
SSLProxyEngine On

# Proxy configuration
ProxyRequests Off
ProxyPreserveHost On

<Proxy *>
Require all granted
</Proxy>

# Allow special characters in headers
AllowEncodedSlashes NoDecode
# Allow any size file to be uploaded
LimitRequestBody 0

# Disable buffering
SetEnv proxy-sendcl 1
SetEnv proxy-sendchunks 1

# Proxy for MinIO S3
ProxyPass / https://localhost:9000/
ProxyPassReverse / https://localhost:9000/

# Proxy for MinIO Console
ProxyPass /minio/ui/ https://localhost:9001/minio/ui/
ProxyPassReverse /minio/ui/ https://localhost:9001/minio/ui/

# Headers
Header always set X-Real-IP %{REMOTE_ADDR}e
Header always set X-Forwarded-For %{REMOTE_ADDR}e
Header always set X-Forwarded-Proto %{HTTP:X-Forwarded-Proto}e
Header always set Host %{HTTP_HOST}e

# To support websockets in MinIO versions released after January 2023
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) wss://localhost:9001/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) https://localhost:9001/$1 [P,L]
</VirtualHost>
1
2
3
4
5
6
7
8
9
10
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
sudo a2enmod headers
service apache2 restart
apt install certbot python3-certbot-apache
sudo certbot certonly --apache -d your.domain
service apache2 restart

Enable SSL for localhost

If you want to make secure level as True, which means use ssl when transport data towards Minio server, you need to make and deploy SSL certificate for Minio.

Log in your server as root.

1
2
3
4
5
6
7
8
su - minio-user
wget https://github.com/minio/certgen/releases/latest/download/certgen-linux-amd64 # find the latest url in https://github.com/minio/certgen
mv certgen-linux-amd64 certgen
chmod +x certgen
./certgen -host "localhost,your.domain"
cp public.crt .minio/certs/
cp private.key .minio/certs/
service minio restart

How to use Minio

Go to your web dashboard with your domain. Login with your username and password defined before.

Screenshot 2024-07-06 at 15.50.01

Click Create Bucket to create your first bucket.

Screenshot 2024-07-06 at 15.51.39

Then make a name for your bucket. Below are some feature you can turn on or off. Let me introduce these for you.

Minio can keep different version of each file when they are uploaded multi-time. It just like time machine in Mac OS. Exclude Folders and Prefixes means these folders or file with prefixes don't need versioning feature. It is highly recommended for you to turn on in case you upload a file with the same name which already in bucket.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

```Object Locking```: If you turn this on, you cannot delete any file in this bucket.

```Quota```: This define the max number of files this bucket could contain.

```Retention```: If this set as ```n```, all the files in this bucket must be kept for ```n``` days.

![Screenshot 2024-07-06 at 15.58.24](./images/Screenshot%202024-07-06%20at%2015.58.24.png)

Then go to ```Access Keys``` page and create an access key for yourself.

![Screenshot 2024-07-06 at 16.09.46](./images/Screenshot%202024-07-06%20at%2016.09.46.png)

If you turn on versioning feature on before, you can select file and click ```Display Object Versions``` to view different version of this file.

![Screenshot 2024-07-06 at 16.11.37](./images/Screenshot%202024-07-06%20at%2016.11.37.png)

We can download or restore different version of file.

## How to upload file using python API

Below is a python demo program shows how to upload file using python API.

Remember before you create both public.crt and private.key, now you need to download public.crt file for SSL connection.

```python
# this program shows how to download file from url and upload this file using python API. After uploading, this program will delete downloaded file.
import os
import requests
from urllib.parse import urlparse
from minio import Minio
from minio.error import S3Error
import urllib3

# maybe your path of public.crt is different, just changed it based on your situation.
httpClient = urllib3.PoolManager(cert_reqs='CERT_REQUIRED',
ca_certs='./public.crt')


def download_file(url, directory, proxy):
try:
# get file name from url
filename = os.path.basename(url)

# create directory for saving file
local_path = os.path.join(save_directory, filename)

response = requests.get(url, stream=True)
if response.status_code == 200:
with open(local_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"File downloaded: {local_path}")
else:
response.raise_for_status()

return local_path
except Exception as e:
print(f"An error occurred while downloading {url}: {e}")
return False


def upload_to_minio(local_path, bucket_name, object_name, minio_client, url):
try:
# Set metadata
metadata = {"x-amz-meta-url": url}

# Upload file to MinIO with metadata
minio_client.fput_object(bucket_name,
object_name,
local_path,
metadata=metadata)
print(
f"'{object_name}' is successfully uploaded to bucket '{bucket_name}' with metadata."
)
except S3Error as err:
print(f"Error occurred: {err}")


def delete_local_file(local_path):
try:
os.remove(local_path)
print(f"Local file '{local_path}' deleted successfully.")
except OSError as e:
print(f"Error deleting file '{local_path}': {e}")


if __name__ == "__main__":
# Specify the URL of the file to download
url = "your_url"

# Specify the directory to save the downloaded file
directory = "./Downloads"

# MinIO server details
minio_endpoint = "your_domain:9000"
access_key = "your_access_key"
secret_key = "your_secret_key"
secure = True # Set to True if using HTTPS

# Initialize MinIO client
minio_client = Minio(minio_endpoint,
access_key=access_key,
secret_key=secret_key,
secure=secure,
http_client=httpClient)

# Specify the bucket name
bucket_name = "your_bucket_name"

# Download the file
local_path = download_file(url, directory)

# Upload the file to MinIO
object_name = os.path.basename(
local_path) # Use the filename as the object name

upload_to_minio(local_path, bucket_name, object_name, minio_client, url)

# Delete the local file to free up disk space
delete_local_file(local_path)

Reference

  1. https://min.io/download?license=agpl&platform=linux

  2. https://min.io/docs/minio/linux/operations/install-deploy-manage/deploy-minio-single-node-single-drive.html

  3. https://min.io/docs/minio/linux/operations/install-deploy-manage/deploy-minio-single-node-single-drive.html

  4. https://github.com/eco-minio/cookbook/blob/master/docs/zh_CN/setup-apache-http-proxy-with-minio.md

  5. https://blog.csdn.net/m0_63004124/article/details/138676505

  6. https://blog.csdn.net/weixin_40547993/article/details/110682587

  7. https://www.qixinbo.info/2023/03/12/minio/

  8. https://github.com/minio/certgen

  9. https://min.io/docs/minio/linux/operations/network-encryption.html

  10. https://github.com/minio/minio/issues/13170

  11. https://github.com/minio/minio-py/issues/730

  12. https://juejin.cn/post/7124571522315845645