使用 rclone serve 搭建S3文件服务器

好不好用,全靠网络,无他!!!

使用小结

OCI上自建Serve S3与GoogleDrive在国内使用,要看网络;(移动)网络不好速度很慢,而oneDrive没有这情况。否则,S3与GoogleDrive,和oneDrive对比在check list的时间长很多。

移动网络

rclone.exe bisync D:\CloudFiles oneDrive: --filter-from rclone_AIO.filter --ignore-case --progress --verbose --log-file Logs\260119.log --recover
Transferred:              0 B / 0 B, -, 0 B/s, ETA -
Checks:               680 / 680, 100%, Listed 754
Elapsed time:         8.6s

rclone.exe bisync D:\Documents\AI-Energize myS3:ai-energize --progress --verbose --log-file Logs\260119.log --recover
Transferred:              0 B / 0 B, -, 0 B/s, ETA -
Checks:               584 / 584, 100%, Listed 669
Elapsed time:      1m57.3s

电信与联通双线

rclone.exe bisync D:\Users\OneDrive\Sysinternals oneDrive:Sysinternals --progress --verbose --log-file Logs\260119.log --recover
Transferred:        3.709 KiB / 3.709 KiB, 100%, 0 B/s, ETA -
Checks:               157 / 157, 100%, Listed 199
Transferred:            1 / 1, 100%
Elapsed time:         7.7s

rclone.exe bisync D:\Users\Obsidian\AI-Energize myS3:ai-energize --progress --verbose --log-file D:\Users\Rclone\Logs\260119.log --recover
Transferred:      197.679 KiB / 197.679 KiB, 100%, 11.279 KiB/s, ETA 0s
Checks:               561 / 561, 100%, Listed 701
Transferred:           23 / 23, 100%
Elapsed time:        35.4s

背景

rclone serve s3 一个轻量级的 S3 协议兼容服务器,用于将本地文件系统暴露为 S3 接口。目标是 协议兼容性(支持 ListBucket、PutObject、Multipart Upload 等),不是构建一个完整的对象存储平台,也不支持IAM、ACL等等。

  • 准确来说rclone serve s3是一个协议适配器,不是一个对象存储系统。
  • rclone serve s3 会将根目录下的所有目录视为存储桶,并忽略根目录下的所有文件。 你可以使用 CreateBucket 在根目录下创建文件夹,但不能在非根目录的其他文件夹下创建空文件夹。
  • 如果你需要真正的多租户、细粒度权限控制,应使用 MinIO 而非 rclone serve s3

serve s3 配置文件

方法一:

$ rclone config create Local local
$ sudo mv ~/.config/rclone/rclone.conf ./
$ sudo chown nginx:adm rclone.conf

方法二:sudo -u nginx vim rclone.conf,再贴上以下的内容。

[Local]
type = local

serve s3 验证

命令行中启动服务器

要提前在OS与Cloud中开放8000端口,官方文档参数说明:英文中文

# --auth-key accessKey,secretKey
# 后续使用nginx反向代理,就不需要参数:--cert cert.pem --key privkey.pem
sudo -u nginx rclone serve s3 --auth-key ACCESS_KEY_ID,SECRET_ACCESS_KEY Local:/data/www/s3Files --config /data/www/s3Files/rclone.conf --addr :8000 --verbose --log-file /data/www/log/s3Files.log

客户端验证:rclone

rclone.conf文件内容:

[myS3]
type = s3
provider = Rclone
endpoint = http://IP:8000/
access_key_id = ACCESS_KEY_ID
secret_access_key = SECRET_ACCESS_KEY
use_multipart_uploads = false

执行验证:rclone lsd myS3:

  • CreateBucket时要注意,名称只能是a~z0~9-组成,不能有大写或其他特殊字符;而文件无此限制。
  • 你可以使用 CreateBucket 在根目录下创建文件夹,但不能在非根目录的其他文件夹下创建空文件夹。
D:\>rclone.exe mkdir myS3:Abc
2026/01/08 21:08:25 ERROR : Attempt 1/3 failed with 1 errors and: operation error S3: CreateBucket, https response error StatusCode: 400, RequestID: xxx, api error InvalidBucketName: bucket must start and end with 'a-z, 0-9', and contain only 'a-z, 0-9, -' in between

D:\>rclone.exe mkdir myS3:abc
D:\>rclone.exe lsd myS3:
          -1 2026-01-09 05:29:54        -1 abc
D:\>rclone.exe mkdir myS3:abc\A_C
2026/01/08 21:36:19 NOTICE: S3 bucket abc path A_C: Warning: running mkdir on a remote which can't have empty directories does nothing

客户端验证:Windows下还有S3 Browser

为rclone serve s3配置反向代理与服务化

nginx + https

server {
    listen 80;
    http2 on;
    server_name  s3.t725.cn;
    access_log off;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl; # managed by Certbot
    http2 on;
    server_name s3.t725.cn;
    ssl_certificate /etc/letsencrypt/live/s3.t725.cn/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/s3.t725.cn/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    # 使用logrotate定期自动切割nginx日志文件,见:blog.t725.cn/?p=1867
    access_log /var/log/nginx/access_s3.725.cn.log main;

    root   /data/www/html;
    index  index.html;
    client_max_body_size 20m; # 上传文件大小上限,超过rclone客户端会报错:413
    add_header X-Frame-Options SAMEORIGIN; # 只允许同源域名下 frame 来嵌套
    add_header X-XSS-Protection "1; mode=block"; # 防止 XSS
    add_header X-Content-Type-Options nosniff; # 禁止嗅探 MIME 类型
    
    if ($http_user_agent = -) { return 444; }
    if ($http_user_agent = "") { return 444; }
    #location ^~ /. { return 444; } # 非法的URI请求,但会和SSL验证/.well-known/有冲突
    location / {
        # proxy_request_buffering on(默认):NGINX 会在转发请求前,先将整个请求体读完并缓存在本地。off:NGINX 会边读取请求体边转发到后端,即流式转发。
        proxy_request_buffering off;
        proxy_pass http://127.0.0.1:8000;
        
        # 支持 WebSocket 协议,但rclone serve s3 不使用、也不需要 WebSocket,核心依赖标准 HTTP/HTTPS 协议;另外,S3 协议本身是 RESTful 设计,无 WebSocket 依赖。
        # 开启前,需要先确认后端服务所支持http version是多少。proxy_http_version可使用值有1.0/1.1/2,但WebSocket至少要1.1。
        #proxy_http_version 2;
        #proxy_read_timeout 1800s;
        #proxy_set_header Upgrade $http_upgrade;
        #proxy_set_header Connection "upgrade";
        
        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_redirect off;
    }

}

systemctl Unit

由于本机nginx反向代理,所以--addr 127.0.0.1:8000,两个Key在客户端上要用到 --auth-key "ACCESS_KEY_ID,SECRET_ACCESS_KEY"。另外,rclone自带的日志轮转参数,所以不需要使用logrotate。具体参数含义如下:

    --log-file /data/www/log/s3Files.log \
    --log-file-max-size 100M \ # 单个日志文件最大大小
    --log-file-max-backups 14 \ # 保留的历史日志文件数量,超过数量的最旧文件会被自动删除,默认0(不保留历史文件)
    --log-file-max-age 14d \ # 日志文件最大保留时间,超过14天的日志文件会被自动删除;可用单位s(秒)、m(分钟)、h(小时)、d(天)、w(周)、y(年),默认0s(久保留),与max-backups关系:两者同时生效,任一条件满足即删除
    --log-file-compress # 启用日志文件压缩
    --log-level INFO # 将 --verbose 替换为 --log-level INFO,提供更结构化的日志

服务注册:sudo vim /usr/lib/systemd/system/rclone-s3.service,文件内容如下:

[Unit]
Description=Rclone S3 Service
Documentation=https://rclone.org/commands/rclone_serve_s3/
After=network.target

[Service]
Type=simple
User=nginx
Group=nginx
ExecStart=/usr/bin/rclone serve s3 \
    --auth-key "ACCESS_KEY_ID,SECRET_ACCESS_KEY" \
    Local:/data/www/s3Files \
    --config /data/www/s3Files/rclone.conf \
    --addr 127.0.0.1:8000 \
    --log-file /data/www/log/s3Files.log \
    --log-file-max-size 10M \
    --log-file-max-backups 9 \
    --log-level INFO
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=rclone-s3
WorkingDirectory=/data/www/s3Files
Environment="PATH=/usr/bin:/bin"

# 安全加固
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/data/www/s3Files /data/www/log
ReadOnlyPaths=/
ProtectHome=true

[Install]
WantedBy=multi-user.target

服务操作:

# 重新加载systemd配置
sudo systemctl daemon-reload
# 启动/停止/查看 服务
sudo systemctl start|stop|status rclone-s3
# 查看实时日志
sudo journalctl -u rclone-s3 -f
# 启用/禁用开机自启
sudo systemctl enable|disable rclone-s3
# 查看进程
ps -Ao user,pid,ppid,%mem,rss,%cpu,cmd|grep -E 'PID|rclone'

在rclone客户端同步大于1M文件报错:413

D:\>D:\Users\Rclone\rclone.exe copy D:\Users\Obsidian\AI-Energize myS3:ai-energize -P -v
2026/01/13 09:14:03 ERROR : 需求方案/LSDWMS-58383 德邦快递的面单改造支持 毛估量级.xlsx: Failed to copy: operation error S3: PutObject, https response error StatusCode: 413, RequestID: , HostID: , error while deserializing xml error response : XML syntax error on line 6: element <hr> closed by </body>

413 Status Code 这个 HTTP 状态码的含义是关键,先明确 413 是 Request Entity Too Large,也就是请求实体过大,服务器无法处理,这是基础根因的切入点。

rclone serve s3 不是真正的 AWS S3,它是模拟 S3 接口的服务,所以报错里的 XML 反序列化异常不是核心,而是附带问题,得先区分主次,避免用户被误导。为什么会有 XML 语法错误?因为 rclone serve s3 在返回 413 错误时,可能没有返回标准的 S3 XML 错误响应,而是返回了普通的 HTTP/html 错误页面(里面有<hr></body>这些 HTML 标签),客户端按 XML 去解析,自然就报错了,这个要先解释清楚,让用户明白核心是 413,不是 XML 解析问题。

由于服务端是经过Nginx反向代理,而默认情况下只支持1M大小文件。

在nginx 站点配置文件中增加client_max_body_size 20m;解决问题,未来超过20M还是会继续报这个错。

用户验证

  • 一是rclone与Nginx开一个验证就可以了,不需要两个同时开启。
  • 二是rclone两个验证方式的作用与区别,见下表:
特性--htpasswd--auth-key
认证层级HTTP Basic Auth(传输层)自定义 S3 请求签名(应用层)
依赖文件需要 .htpasswd 文件只需一个字符串密钥
客户端兼容性任何支持 Basic Auth 的 HTTP 客户端(包括浏览器、curl、部分 S3 工具)仅 rclone 客户端支持
协议标准标准 HTTP Basic Auth (RFC 7617)rclone 私有签名方案
是否影响 S3 协议否(先过 HTTP 认证,再处理 S3)是(作为 S3 请求合法性的一部分)
典型用途快速加一层密码保护(如配合 Nginx)在 rclone-to-rclone 场景中实现轻量安全通信
  • 对外提供 S3 兼容接口:用 --s3-access-key-id + --s3-secret-access-key(模拟 AWS 凭据)。但注意,rclone中三选一使用就可以了,推荐使用--auth-key,在
$ cat htpasswd.conf
# user:password:comment
liang:$2y$10$CaNIpr0uYQq9P4kXerHUrupevm91/Pbihf9z2QieIJfwA7fU4L5gi:5YJKq9x3V74zfZvo

# Nginx server 增加配置
auth_basic "S3 File Server Authentication"; 
auth_basic_user_file /data/www/s3Files/htpasswd.conf;

# rclone serve s3 增加参数
--htpasswd /data/www/s3Files/htpasswd.conf

liang:5YJKq9x3V74zfZvo  进行base64编码,得到 bGlhbmc6NVlKS3E5eDNWNzR6Zlp2bw==
HTTP请求头就是:Authorization: Basic bGlhbmc6NVlKS3E5eDNWNzR6Zlp2bw==

以下是错误做法的示例,所以客户端连接不上。

  • 在rclone启动命令上增加了htpasswd参数,比如:rclone serve s3 --htpasswd /s3Files/htpasswd.conf --Local:/s3Files --addr 127.0.0.1:8000
  • 在nginx反向代理rclone站点里启动了auth_basicauth_basic_user_file
  • rclone serve s3 服务器的上版本信息
$ rclone version
rclone v1.71.2
- os/version: ubuntu 24.04 (64 bit)
- os/kernel: 6.14.0-1017-oracle (x86_64)
- os/type: linux
- os/arch: amd64
- go/version: go1.25.3
- go/linking: static
- go/tags: none
$ nginx -v
nginx version: nginx/1.28.0

使用curl测试结果:

REM curl -u user:passWD -I https://s3.t725.cn/

D:\>curl -H "Authorization: Basic <The base64 encoding of user:passWD>" -I https://s3.t725.cn/
HTTP/1.1 400 Bad Request
Server: nginx/1.28.0
Date: Sun, 11 Jan 2026 09:59:25 GMT
Content-Type: text/xml; charset=utf-8
Content-Length: 143
Connection: keep-alive


D:\>curl -I https://s3.t725.cn/
HTTP/1.1 401 Unauthorized
Server: nginx/1.28.0
Date: Sun, 11 Jan 2026 09:59:37 GMT
Content-Type: text/html
Content-Length: 179
Connection: keep-alive
WWW-Authenticate: Basic realm="S3 File Server Authentication"

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注