One Server

문서

파일

버킷과 업로드, 공개와 비공개의 차이, S3로 쓰기, Supabase에서 파일 옮기기, 이어 올리기(TUS).

파일

POST   /storage/v1/bucket                    {"id":"avatars","public":true}
POST   /storage/v1/object/avatars/<이름>      본문: 파일 바이트
GET    /storage/v1/object/avatars/<이름>
DELETE /storage/v1/object/avatars/<이름>

공개 버킷과 비공개 버킷

public: true인 버킷의 파일은 누구나 받을 수 있고 CDN이 캐시해요. 그렇지 않은 버킷은 올린 사람만 받을 수 있고 캐시되지 않아요.

프로필 사진처럼 이미 공개된 것은 공개 버킷, 그 외에는 비공개가 기본이에요.

Supabase용으로 쓴 파일 규칙도 그대로 써요. storage.foldername(name), storage.filename(name), storage.extension(name)과 storage.buckets의 name·owner 열이 있어서, (storage.foldername(name))[1] = auth.uid()::text 같은 조건을 콘솔의 [접근 규칙] 화면, Supabase에서 옮기기, 또는 SQL 편집기·run_sql·마이그레이션의 create policy … on storage.objects로 넣으면 이 프로젝트의 이름으로 바뀌어 동작해요. SQL로 넣으면 나머지 SQL이 끝난 뒤 One Server가 그 규칙을 만들어요.

S3로 쓰기

AWS SDK, aws CLI, rclone처럼 S3를 쓰는 도구로 같은 버킷을 다뤄요. REST로 올린 파일이 S3에 보이고, 그 반대도 같아요.

endpoint:        https://<ref>.<zone>/storage/v1/s3
region:          ap-northeast-2
forcePathStyle:  true

접근 키는 create_s3_key로 만들고(비밀 접근 키는 그 응답에만 있어요), list_s3_keys로 보고, revoke_s3_key로 폐기해요. 접근 키는 서비스 역할이라 접근 규칙(RLS)을 무시해요. 서버에만 두세요.

앱 사용자의 권한으로 쓰려면 세션 토큰 방식이에요: 접근 키 ID에 프로젝트 ref, 비밀 접근 키에 공개 키(bw_publishable_…), 세션 토큰에 사용자의 액세스 토큰을 넣어요. 그 사용자의 접근 규칙이 그대로 적용돼요.

ListBuckets, CreateBucket, DeleteBucket, HeadBucket, ListObjectsV2, GetObject(Range), HeadObject, PutObject, CopyObject, DeleteObject(s), 멀티파트 업로드를 지원해요. 버전 관리·ACL·태그·수명 주기는 NotImplemented로 답해요.

Supabase에서 파일 옮기기

Supabase Storage도 S3로 열 수 있어서, rclone 하나로 버킷을 통째로 옮겨요. 경로가 그대로라 표에 저장된 파일 경로(avatars/123.png)는 바꾸지 않아도 돼요.

1. 여기에 같은 이름의 버킷을 먼저 만들어요(create_bucket). 공개 여부도 Supabase와 같게 골라요. 2. Supabase 대시보드의 Storage 설정에서 S3 접근 키를 만들고, 여기서는 create_s3_key로 만들어요. 3. rclone 설정(~/.config/rclone/rclone.conf)에 두 곳을 적어요.

[supabase]
type = s3
provider = Other
endpoint = https://<supabase-ref>.supabase.co/storage/v1/s3
region = <Supabase 프로젝트의 리전>
access_key_id = <Supabase 접근 키 ID>
secret_access_key = <Supabase 비밀 접근 키>

[oneend]
type = s3
provider = Other
endpoint = https://<ref>.<zone>/storage/v1/s3
region = ap-northeast-2
access_key_id = <create_s3_key의 접근 키 ID>
secret_access_key = <create_s3_key의 비밀 접근 키>

4. 버킷마다 복사해요. 다시 실행하면 바뀐 파일만 보내요.

rclone copy supabase:avatars oneend:avatars --progress
rclone check supabase:avatars oneend:avatars   # 빠진 파일이 없는지 확인

aws CLI만 있으면 내려받았다가 올려요.

aws s3 sync s3://avatars ./avatars --endpoint-url https://<supabase-ref>.supabase.co/storage/v1/s3
aws s3 sync ./avatars s3://avatars --endpoint-url https://<ref>.<zone>/storage/v1/s3

파일 하나의 최대 크기는 요금제를 따라요(무료 50MB, Pro 5GB). 공개 주소는 https://<ref>.<zone>/storage/v1/object/public/<버킷>/<경로>로 바뀌니, 표에 전체 주소를 저장했다면 그 주소만 고쳐요.

이어 올리기(TUS)

큰 파일은 TUS로 올리면 연결이 끊겨도 이어서 보낼 수 있어요. tus-js-client나 Uppy를 그대로 써요.

endpoint:  https://<ref>.<zone>/storage/v1/upload/resumable
headers:   Authorization: Bearer <key or access token>, x-upsert: true
metadata:  bucketName, objectName, contentType, cacheControl

하루 동안 이어 받지 않은 업로드는 만료되고 지워져요. 일반 업로드도 S3·TUS로 올리는 파일 하나도 요금제 한도(무료 50MB, Pro 5GB)를 따르고, 버킷 한도가 더 작으면 그걸 따라요.

도구로 파일 다루기

list_objects        버킷 안의 폴더 보기 (prefix, search)
upload_object       파일 하나 올리기 (2MB까지, 바이너리는 base64)
download_object     파일 하나 받기 (2MB까지)
delete_object       파일 하나 지우기
create_signed_url   비공개 파일을 정해진 시간 동안 받을 수 있는 주소 (최대 7일)
create_upload_url   큰 파일(이미지·영상)을 PUT으로 올릴 주소 (2시간, 한 파일)
update_bucket       버킷의 공개 여부, 파일 크기 한도, 받을 형식 바꾸기
empty_bucket        버킷 안의 파일 모두 지우기 (confirm에 버킷 이름)
delete_bucket       빈 버킷 지우기 (confirm에 버킷 이름)

더 큰 파일은 위의 /storage/v1 주소로 올리고 받아요.

이미지·영상은 내용을 도구 인자로 보내지 말고 create_upload_url로 주소를 받아 그 url에 PUT해요: curl -X PUT -H 'content-type: video/mp4' --data-binary @./intro.mp4 '<url>'. 한 번에 max_bytes(요금제의 파일 하나 한도: 무료 50MB, Pro 5GB. 버킷 한도가 더 작으면 그것)까지 올려요. 느린 회선에서 큰 파일은 끊긴 곳부터 잇는 이어 올리기(TUS)가 편해요. REST로는 POST /v1/projects/<ref>/buckets/<버킷>/upload-urls이에요.

버킷을 만들 때(create_bucket)나 나중에(update_bucket) file_size_limit(예: "5MB")와 allowed_mime_types(예: ["image/*"])로 받을 파일을 정해요. 버킷을 지우려면 먼저 empty_bucket으로 비우고, delete_bucket의 confirm에 버킷 이름을 그대로 넣어요. empty_bucket도 confirm에 버킷 이름을 받아요. 되돌릴 수 없는 도구는 모두 이렇게 confirm에 지울 것의 이름을 받아요: empty_bucket, delete_queue, purge_queue, reset_branch, delete_branch, remove_function, remove_domain, delete_gpu_server, disable_extension, remove_user(이메일 또는 id), reset_database_password·set_spend_cap(끌 때)·rotate_signing_key(grace_hours: 0일 때)는 프로젝트 이름. 틀리거나 비우면 무엇을 넣어야 하는지 알려 주며 거절해요. REST로는 PATCH /v1/projects/<ref>/buckets/<버킷>, POST /v1/projects/<ref>/buckets/<버킷>/empty, DELETE /v1/projects/<ref>/buckets/<버킷> {confirm}이에요.

저장소 설정, 이전 버전, 배포에 연결한 버킷

get_storage_settings      파일 하나 최대 크기, 이미지 변환, S3 주소, 버킷마다 버전 보관
set_storage_settings      프로젝트 전체의 파일 크기 한도와 이미지 변환 (빠진 항목은 그대로)
set_s3_enabled            S3 주소 켜기·끄기 (키는 남아요)
set_bucket_versioning     버킷이 덮어쓴·지운 파일을 이전 버전으로 남길지, 며칠 둘지
list_object_versions      이전 버전 목록 (name을 주면 그 파일만)
restore_object_version    이전 버전을 지금 파일로 되돌리기
remove_object_version     이전 버전 영구 삭제 (confirm에 파일 이름)
list_bucket_connections   배포에 연결한 버킷과 넣는 환경 변수
connect_bucket            버킷 하나만 여는 S3 키를 배포의 <접두어>_BUCKET 등으로 넣기
disconnect_bucket         연결의 키를 폐기하고 변수 빼기 (confirm에 접두어)
list_storage_policies     파일 표(objects)·버킷 표(buckets)의 접근 규칙
create_storage_policy     콘솔의 틀(public-read, signed-in-read, own-folder …)이나 직접 쓴 규칙 만들기
remove_storage_policy     규칙 삭제 (confirm에 규칙 이름, 기본 규칙은 못 지워요)

파일 표의 규칙은 run_sql로 만들 수 없어서 create_storage_policy를 써요. 조건식의 auth.uid()는 uid()로 바뀌어요. production에 넣는 연결과 끊기는 소유자·관리자만, 나머지는 개발자 이상이 할 수 있어요. 무료 요금제에는 없어요.