From b5b733d7e7a78c501ef8b41ece81831fa01b6028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Fojt=C3=ADk?= Date: Sun, 14 Jun 2026 10:36:35 +0200 Subject: [PATCH] feat: add support for RustFS S3 --- apps/nestjs-backend/src/configs/storage.ts | 1 + .../src/features/attachments/plugins/s3.ts | 4 +- apps/nextjs-app/.env.development | 12 +++++ dockers/.env | 6 ++- dockers/storage-rustfs.yml | 53 +++++++++++++++++++ 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 dockers/storage-rustfs.yml diff --git a/apps/nestjs-backend/src/configs/storage.ts b/apps/nestjs-backend/src/configs/storage.ts index 4106347735..00f36d7cff 100644 --- a/apps/nestjs-backend/src/configs/storage.ts +++ b/apps/nestjs-backend/src/configs/storage.ts @@ -33,6 +33,7 @@ export const storageConfig = registerAs('storage', () => ({ accessKey: process.env.BACKEND_STORAGE_S3_ACCESS_KEY!, secretKey: process.env.BACKEND_STORAGE_S3_SECRET_KEY!, maxSockets: Number(process.env.BACKEND_STORAGE_S3_MAX_SOCKETS ?? 100), + forcePathStyle: process.env.BACKEND_STORAGE_S3_FORCE_PATH_STYLE === 'true', }, uploadMethod: process.env.BACKEND_STORAGE_UPLOAD_METHOD ?? 'put', encryption: { diff --git a/apps/nestjs-backend/src/features/attachments/plugins/s3.ts b/apps/nestjs-backend/src/features/attachments/plugins/s3.ts index 7340a2de68..2fca512292 100644 --- a/apps/nestjs-backend/src/features/attachments/plugins/s3.ts +++ b/apps/nestjs-backend/src/features/attachments/plugins/s3.ts @@ -35,7 +35,7 @@ export class S3Storage implements StorageAdapter { private logger = new Logger(S3Storage.name); constructor(@StorageConfig() readonly config: IStorageConfig) { - const { endpoint, region, accessKey, secretKey, maxSockets } = this.config.s3; + const { endpoint, region, accessKey, secretKey, maxSockets, forcePathStyle } = this.config.s3; this.checkConfig(); this.httpsAgent = new https.Agent({ maxSockets, @@ -50,6 +50,7 @@ export class S3Storage implements StorageAdapter { region, endpoint, requestHandler, + forcePathStyle, credentials: { accessKeyId: accessKey, secretAccessKey: secretKey, @@ -64,6 +65,7 @@ export class S3Storage implements StorageAdapter { endpoint, bucketEndpoint: true, requestHandler, + forcePathStyle, credentials: { accessKeyId: accessKey, secretAccessKey: secretKey, diff --git a/apps/nextjs-app/.env.development b/apps/nextjs-app/.env.development index 806a5b602a..6260c39c43 100644 --- a/apps/nextjs-app/.env.development +++ b/apps/nextjs-app/.env.development @@ -10,6 +10,18 @@ NEXT_BUILD_ENV_SENTRY_UPLOAD_DRY_RUN=false BACKEND_STORAGE_PROVIDER=local BACKEND_STORAGE_PUBLIC_BUCKET=public BACKEND_STORAGE_PUBLIC_URL=http://localhost:3000/api/attachments/read/public + +# Example of configuration for RustFS +#BACKEND_STORAGE_PROVIDER=s3 +#BACKEND_STORAGE_PUBLIC_BUCKET=public +#BACKEND_STORAGE_PUBLIC_URL=http://localhost:9000 +#BACKEND_STORAGE_S3_REGION=eu +#BACKEND_STORAGE_S3_ENDPOINT=http://localhost:9000 +#BACKEND_STORAGE_S3_INTERNAL_ENDPOINT=http://localhost:9000 +#BACKEND_STORAGE_S3_ACCESS_KEY=teable +#BACKEND_STORAGE_S3_SECRET_KEY=teable123 +#BACKEND_STORAGE_S3_FORCE_PATH_STYLE=true + # ↓↓↓↓↓↓↓↓ backend(nestjs) env ↓↓↓↓↓↓↓↓ NEXTJS_DIR=../nextjs-app LOG_LEVEL=info diff --git a/dockers/.env b/dockers/.env index 039af31256..f05cb7627d 100644 --- a/dockers/.env +++ b/dockers/.env @@ -10,4 +10,8 @@ REDIS_PASSWORD=teable # Minio env MINIO_ACCESS_KEY=teable -MINIO_SECRET_KEY=teable123 \ No newline at end of file +MINIO_SECRET_KEY=teable123 + +# RustFS S3 +RUSTFS_ACCESS_KEY=teable +RUSTFS_SECRET_KEY=teable123 diff --git a/dockers/storage-rustfs.yml b/dockers/storage-rustfs.yml new file mode 100644 index 0000000000..003065a097 --- /dev/null +++ b/dockers/storage-rustfs.yml @@ -0,0 +1,53 @@ +name: teable-storage + +services: + teable-storage: + image: rustfs/rustfs:latest + container_name: teable-storage + hostname: teable-storage + restart: always + ports: + - '9000:9000' + - '9001:9001' + environment: + - RUSTFS_ADDRESS=:9000 + - RUSTFS_CONSOLE_ADDRESS=:9001 + - RUSTFS_ACCESS_KEY=${RUSTFS_ACCESS_KEY} + - RUSTFS_SECRET_KEY=${RUSTFS_SECRET_KEY} + - RUSTFS_CONSOLE_ENABLE=true + - RUSTFS_CORS_ALLOWED_ORIGINS=* + - RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=* + volumes: + - storage_data:/data:rw + - storage_data:/logs:rw + # you may use a bind-mounted host directory instead, + # so that it is harder to accidentally remove the volume and lose all your data! + # - ./docker/storage/data:/data:rw + healthcheck: + test: + [ + "CMD", + "sh", "-c", + "curl -f http://127.0.0.1:9000/health && curl -f http://127.0.0.1:9001/rustfs/console/health" + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + createbuckets: + image: minio/mc + depends_on: + - teable-storage + entrypoint: > + /bin/sh -c " + /usr/bin/mc alias set teable-storage http://teable-storage:9000 ${RUSTFS_ACCESS_KEY} ${RUSTFS_SECRET_KEY}; + /usr/bin/mc mb teable-storage/public; + /usr/bin/mc anonymous set public teable-storage/public; + /usr/bin/mc mb teable-storage/private; + exit 0; + " + +volumes: + storage_data: + storage_logs: