feat: add configurable S3 object storage

This commit is contained in:
237899745
2026-07-25 13:23:11 +08:00
parent 61fa9cb820
commit d1f093685d
29 changed files with 3703 additions and 284 deletions

View File

@@ -0,0 +1,56 @@
name: imageforge-storage
services:
garage:
image: dxflrs/garage:v2.3.0
command: ["/garage", "server", "--single-node"]
restart: unless-stopped
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
pids_limit: 256
mem_limit: 1200m
cpus: 1.75
ports:
- "127.0.0.1:3900:3900"
- "10.70.0.2:3900:3900"
- "10.70.0.2:3901:3901"
- "127.0.0.1:3903:3903"
volumes:
- ./garage.toml:/etc/garage.toml:ro
- /srv/garage/meta:/var/lib/garage/meta
- /srv/garage/data:/var/lib/garage/data
- /srv/garage/snapshots:/var/lib/garage/snapshots
secrets:
- source: garage_rpc_secret
target: garage_rpc_secret
mode: 0400
- source: garage_admin_token
target: garage_admin_token
mode: 0400
- source: garage_metrics_token
target: garage_metrics_token
mode: 0400
tmpfs:
- /tmp:size=64m,mode=1777
healthcheck:
test: ["CMD", "/garage", "status"]
interval: 15s
timeout: 5s
retries: 10
start_period: 20s
logging:
driver: json-file
options:
max-size: "20m"
max-file: "3"
secrets:
garage_rpc_secret:
file: ./secrets/garage_rpc_secret
garage_admin_token:
file: ./secrets/garage_admin_token
garage_metrics_token:
file: ./secrets/garage_metrics_token

View File

@@ -0,0 +1,37 @@
replication_factor = 1
consistency_mode = "consistent"
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
metadata_snapshots_dir = "/var/lib/garage/snapshots"
metadata_fsync = true
data_fsync = false
metadata_auto_snapshot_interval = "12h"
use_local_tz = false
# The first node is small and traffic is currently low. SQLite avoids a large
# memory map; a future multi-node rollout can use LMDB on the new nodes.
db_engine = "sqlite"
block_size = "1M"
block_ram_buffer_max = "64MiB"
block_max_concurrent_reads = 8
block_max_concurrent_writes_per_request = 3
# JPEG, PNG, WebP, AVIF and ZIP outputs are already compressed.
compression_level = 'none'
rpc_secret_file = "/run/secrets/garage_rpc_secret"
rpc_bind_addr = "[::]:3901"
rpc_public_addr = "10.70.0.2:3901"
bootstrap_peers = []
[s3_api]
api_bind_addr = "[::]:3900"
s3_region = "garage"
root_domain = ".s3.garage.internal"
[admin]
api_bind_addr = "[::]:3903"
admin_token_file = "/run/secrets/garage_admin_token"
metrics_token_file = "/run/secrets/garage_metrics_token"
metrics_require_token = true

View File

@@ -0,0 +1,46 @@
{
"Rules": [
{
"ID": "results-1d-safety",
"Status": "Enabled",
"Filter": { "Prefix": "results/1d/" },
"Expiration": { "Days": 3 }
},
{
"ID": "archives-1d-safety",
"Status": "Enabled",
"Filter": { "Prefix": "archives/1d/" },
"Expiration": { "Days": 3 }
},
{
"ID": "results-7d-safety",
"Status": "Enabled",
"Filter": { "Prefix": "results/7d/" },
"Expiration": { "Days": 9 }
},
{
"ID": "archives-7d-safety",
"Status": "Enabled",
"Filter": { "Prefix": "archives/7d/" },
"Expiration": { "Days": 9 }
},
{
"ID": "results-15d-safety",
"Status": "Enabled",
"Filter": { "Prefix": "results/15d/" },
"Expiration": { "Days": 17 }
},
{
"ID": "archives-15d-safety",
"Status": "Enabled",
"Filter": { "Prefix": "archives/15d/" },
"Expiration": { "Days": 17 }
},
{
"ID": "abort-incomplete-multipart",
"Status": "Enabled",
"Filter": { "Prefix": "" },
"AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 1 }
}
]
}

View File

@@ -0,0 +1,45 @@
server {
listen 80;
listen [::]:80;
server_name files.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name files.example.com;
ssl_certificate /etc/letsencrypt/live/files.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/files.example.com/privkey.pem;
# Signed URLs contain credentials and signatures. Do not write the query
# string to the standard access log.
access_log off;
location / {
limit_except GET HEAD {
deny all;
}
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Connection "";
proxy_request_buffering off;
proxy_buffering off;
proxy_max_temp_file_size 0;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_pass http://127.0.0.1:3900;
}
add_header X-Content-Type-Options nosniff always;
}