免费的图床服务,不靠谱,免费的总是最贵的,而且免费的将来一定会遇到很多麻烦
付费的图床服务,域名要备案,而且自己的资源很有可能会被服务商看个精光
所以只能自建图床了,自建图床有很多方案,我选择了最纯粹的minio,一个开源的对象存储服务。 之前也折腾过nextcloud,seafile等开源网盘,但是网盘终究是网盘,和minio还是有一定的差距,就凭"权限访问"这个功能,就已经秒杀了网盘。当然网盘也有相应的优势,可是要搭建图床的话,网盘不是首选
为什么选择minio
minio的存储方式采用了S3,S3(Simple Storage Service)是由亚马逊公司开发的一种对象存储服务,由于S3服务的广泛使用和影响力,S3 API已经成为云存储领域的事实标准之一。 S3 API是一种RESTful API,可以用于管理对象存储服务中的数据,包括上传、下载、删除、列出对象等操作。S3 API的主要特点是简单易用、可扩展、高度兼容,因此被广泛应用于各种对象存储服务中。 除了亚马逊公司自己的S3服务之外,许多其他云存储服务提供商也支持S3 API,例如微软的Azure Blob存储、Google Cloud的Cloud Storage等,这些服务都兼容S3 API,使得开发者可以使用相同的API来访问不同的云存储服务。
其中,IAM和ARN是AWS中的两个重要概念。
IAM代表身份和访问管理(Identity and Access Management),它是AWS中用于管理用户、组和角色以及分配权限的服务。IAM使您能够创建和控制谁可以访问您的AWS资源以及他们可以执行哪些操作
ARN代表Amazon资源名称(Amazon Resource Name),用于标识各种资源,如EC2 实例、S3存储桶、IAM角色等。ARN的格式如下
arn:partition:service:region:account-id:resource
partition
用于标识资源所在的分区。对于标准 AWS 区域,分区是 aws。如果资源位于其他分区,则分区是 aws-partitionname。例如,中国(北京)区域中的资源的分区为 aws-cn。您不能在不同分区的账户之间委派访问权限service
AWS服务的简称,例如:ec2、s3、iam等region
AWS区域代码,例如:us-west-1、ap-southeast-2等。(对于 IAM 资源,它始终保持空白)account
AWS账户IDresource
按名称标识特定资源。
ARN示例:
# 表示一个IAM用户
arn:aws:iam::123456789012:user/JohnDoe
# 表示一个名字为example-bucket的s3存储桶
arn:aws:s3:::example-bucket
更多示例在官方文档https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/reference_identifiers.html
有了上面的基础,那么我们就可以写Access Policy了。简单来说,Access Policy定义了哪些人(Preincipal)可以对哪些资源(Resource)进行哪些操作(Effect、Action)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "statement-example",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<account-id>:user/<username>"
]
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::*"
]
}
]
}
Version
"2012-10-17" 指定了策略语法版本号,表示该策略是基于2012年10月17日版本的语法编写的。Statement
[] 是一个数组,包含了一个或多个访问控制规则(Statement)。Sid
Statement id,可以随便写,主要是给当前的statement添加一个注释信息Effect
"Allow" 表示该规则允许访问控制。"Denied"表示拒绝访问Principal
指定IAM用户Action
操作Resource
资源
Amazon提供了一个自动生成policy的网站https://awspolicygen.s3.amazonaws.com/policygen.html
运行minio容器
以docker-compose方式运行在单独的minio_default网络中,其他容器加入网络后使用"minio"可直接访问s3服务
services:
minio:
container_name: minio
image: quay.io/minio/minio
restart: always
volumes:
- $PWD/data:/data
environment:
- TZ=Asia/Shanghai
- MINIO_ROOT_USER=<root用户>
- MINIO_ROOT_PASSWORD=<root密码>
ports:
- "9001:9000"
- "9091:9090"
command: server /data --address ":9000" --console-address ":9090"
--address ":9000"
指定api请求端口,默认9000,或者在启动日志里可以看到默认的api端口号--console-address ":9090"
指定Web管理页面端口。最好设置一下,不然会分配一个随机的端口MINIO_ROOT_USER
MINIO_ROOT_USER
Web页面登录时的用户名和密码-e TZ=Asia/Shanghai
设置中国时区/data
这个文件夹里有minio的配置文件和上传到服务器上的资源(图片、视频...),这个文件千万不能删除,删掉后你的文件就没了
其他内容保持不变,直接运行docker compose up -d
就可以,然后访问http://[服务器ip地址]:[console端口号]
就可以看到登录界面。
问题记录: 浏览器访问console页面返回502,检查端口号有没有被拦截,浏览器是否开了VPN代理
配置匿名访问
- 在web界面创建一个bucket,bucket可以理解成"文件夹"
- 设置bucket的policy为custom,允许所有人(包括匿名用户)可以读取内容,否则html的img标签就无法加载出图片
{ "Version": "2012-10-17", "Statement": [ { "Sid": "allow-anybody-read", "Effect": "Allow", "Principal": { "AWS": [ "*" ] }, "Action": [ "s3:GetObject" ], "Resource": [ "arn:aws:s3:::*" ] } ] }
配置好以后,用你的浏览器试着访问一下bucket中的资源,链接为:http://[服务器ip地址]:[minio的api端口号,默认9000]/[bucket-name]/[file-name]
Nginx反向代理
以下内容出自官方文档:https://min.io/docs/minio/linux/integrations/setup-nginx-proxy-with-minio.html
# Web管理页面
server {
listen 80;
listen 443 ssl http2;
server_name <二级域名,比如admin.example.com>;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privatekey.pem;
# Allow special characters in headers
ignore_invalid_headers off;
# Allow any size file to be uploaded.
# Set to a value such as 1000m; to restrict file size to a specific value
client_max_body_size 0;
# Disable buffering
proxy_buffering off;
proxy_request_buffering off;
location / {
proxy_pass http://localhost:<端口号>;
proxy_set_header Host $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;
# This is necessary to pass the correct IP to be hashed
real_ip_header X-Real-IP;
proxy_connect_timeout 300;
# To support websocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
chunked_transfer_encoding off;
}
}
# api接口
server {
listen 80;
listen 443 ssl http2;
server_name <二级域名,api.example.com>;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privatekey.pem;
# Allow special characters in headers
ignore_invalid_headers off;
# Allow any size file to be uploaded.
# Set to a value such as 1000m; to restrict file size to a specific value
client_max_body_size 0;
# Disable buffering
proxy_buffering off;
proxy_request_buffering off;
location / {
proxy_pass http://localhost:<端口号>;
proxy_set_header Host $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_connect_timeout 300;
# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;
}
}
如果Nginx不是以docker容器运行的,而是单独运行的,您还必须为 MinIO 部署设置以下环境变量:
MINIO_SERVER_URL
设置为minio api地址,如:https://api.example.comMINIO_BROWSER_REDIRECT_URL
设置为minio web管理页面地址,如:https://console.example.com
数据备份
如果你的minio服务器经过了CDN代理,那么在数据备份的时候,一定要使用minio服务器的直接链接(也就是通过url可以直接访问你的minio服务器,不经过cdn中转)这个问题查了我整整两天时间,已经有点崩溃了,是个大坑!!!
使用cdn代理的url进行数据备份,可能会因为cdn服务器的缓存问题,导致备份的数据不是最新的数据!!!
- 下载mc客户端,安装教程在这里
- 创建一个access key
为了安全起见,你可以先创建一个user,有两种方法创建user如果用admin的身份登录web管理界面并创建access key,那么这个access key具有很高的权限,比如 - 列出所有存储桶和对象; - 创建、删除、修改存储桶; - 上传、下载、删除、复制、移动对象; - 获取对象元数据和ACL(访问控制列表)
- 方法一:web管理页面可以直接创建
- 方法二:通过mc客户端创建,ACCESSKEY和SECRETKEY也被用作登录账号和密码
mc admin user add TARGET ACCESSKEY SECRETKEY
-
ACCESSKEY
Also called as username. -
SECRETKEY
Also called as password.新创建的user没有任何权限,我们需要给他分配一些权限,比如:readonly/writeonly/readwrite,只有分配了权限,user才可以访问资源。在这里我们可以给他分配readwrite权限,因为要备份数据
-
- 然后为刚才的access key添加一个别名
例如:mc alias set <ALIAS> <YOUR-S3-API-ENDPOINT> <YOUR-ACCESS-KEY> <YOUR-SECRET-KEY>
或者直接编辑配置文件,macos的配置文件在mc alias set minio https://example.com <YOUR-ACCESS-KEY> <YOUR-SECRET-KEY>
~/.mc/config.json
- 把服务器上的bucket备份到本地,使用
--overwrite
覆盖不一样的内容
比如mc mirror --overwrite <alias>/<bucket-name> <path/to/local/dir>
mc mirror --overwrite minio/article article
- 把本地的bucket备份到服务器,使用
--overwrite
覆盖不一样的内容
比如mc mirror --overwrite <alias>/<bucket-name> <path/to/local/dir>
mc mirror --overwrite minio/article article
避坑
- 访问图片资源时,要使用api的端口号,不能是webUI端口号
- 测试阶段,如果出现奇奇怪怪的问题,就看下你的请求url有没有经过cdn代理
补充
- minio默认允许跨域访问。如果要设置CORS,可以在cdn服务器上设置
- minio默认不开启gzip压缩。不建议minio服务器开启gzip压缩,会影响原始文件大小,如果要开启压缩,可以让cdn服务器进行压缩
minio sdk
官方提供的mc客户端有时候并不能满足我的要求,只能使用api自己完成想要的功能,我选择python sdk
python sdk官方文档链接:https://min.io/docs/minio/linux/developers/python/API.html
安装:pip install minio
功能1-文件夹的重命名/文件夹拷贝
from minio import Minio
from minio.commonconfig import CopySource
client = Minio(endpoint='<服务器的地址:端口>',
access_key='<自己的access_key>',
secret_key='<自己的secret_key>',
secure=False)
def copy_src_to_dest(src,dest):
try:
result = client.list_objects('<bucket名称>', recursive=True,prefix=src)
for obj in result:
print(f'正在将{obj.object_name}复制到{obj.object_name.replace(src,dest)}')
client.copy_object('blog', obj.object_name.replace(src,dest), CopySource("blog", obj.object_name))
print('复制完成')
except OSError as err:
print(err)
secure=False
表示使用http连接src
和dest
相对路径。如果有个文件夹的绝对路径是/<bucket-name>/<article-name>/<year>
,那么只需要写<article-name>/<year>
就行了