# S3 호환성

Storage Buckets는 **S3 호환 API**를 통해 액세스할 수 있어, 코드를 변경하지 않고도 기존 S3 도구인 AWS CLI, `boto3`, `s5cmd` 및 대부분의 기타 S3 SDK를 버킷에 사용할 수 있습니다. 요청은 `https://s3.hf.co`의 게이트웨이 서비스를 통해 전달되며, 각 네임스페이스는 고유한 호스트네임인 `https://<namespace>.s3.hf.co`에서도 제공됩니다.

S3 API는 버킷 데이터에 접근하는 여러 방법 중 하나입니다. 별도의 S3 자격 증명 없이 Hugging Face 네이티브 접근 방식(`hf` CLI, `hf://` 경로, 파일시스템 마운트)에 대해서는 [접근 패턴](./storage-buckets-access)을 참고하세요.

> [!NOTE]
> S3 API는 [Storage Buckets](./storage-buckets)와만 작동합니다. 다른 Hugging Face 저장소 유형(모델, 데이터셋, Spaces)은 노출하지 않습니다.

## S3 자격 증명 생성

게이트웨이는 Hugging Face [사용자 액세스 토큰](./security-tokens)에서 파생된 AWS 스타일 액세스 키로 인증합니다.

1. [Access Tokens 설정](https://huggingface.co/settings/tokens)으로 이동합니다. 아직 토큰이 없다면 **Create new token** 버튼을 눌러 토큰을 생성합니다. 토큰의 권한이 S3 자격 증명의 권한이 됩니다. 버킷에 대한 읽기 전용 액세스를 원하면 **Read**를, 읽기 및 쓰기 액세스를 원하면 **Write**를 선택합니다.
2. 목록에서 토큰을 찾아 드롭다운 메뉴를 열고 **Generate S3 credentials**를 선택합니다.

   
   
   
   

3. 생성된 **access key ID**(`HFAK…` 접두사)와 **secret access key**를 안전한 곳에 복사하세요. secret은 한 번만 표시됩니다.

S3 자격 증명은 기본 액세스 토큰의 권한을 상속합니다. 세분화된 토큰의 경우, 사용할 예정인 네임스페이스와 버킷에만 범위를 지정하세요.

> [!TIP]
> 조직의 버킷에 액세스하는 자동화 워크플로우는 User Access Token 대신 [service account](./enterprise-service-accounts#generating-s3-credentials) 토큰에서 S3 자격 증명을 생성할 수도 있습니다.

## 클라이언트 구성

S3 클라이언트를 게이트웨이 엔드포인트로 지정하고 몇 가지 필수 옵션을 설정합니다. 엔드포인트 URL에는 Hugging Face **namespace**(사용자 이름 또는 조직 이름)를 사용해야 합니다. 자세한 내용은 아래 [Addressing buckets](#addressing-buckets)를 참조하세요.

| 설정                        | 값                          | 왜                                                           |
|--------------------------------|--------------------------------|---------------------------------------------------------------|
| `endpoint_url`                 | `https://<namespace>.s3.hf.co` | 네임스페이스 범위로 설정된 게이트웨이                         |
| `region`                       | `us-east-1`                    | 필수; 게이트웨이는 현재 단일 리전입니다              |
| `s3.addressing_style`          | `path`                         | Buckets는 서브도메인이 아닌 경로 세그먼트로 지정됩니다        |
| `request_checksum_calculation` | `when_required`                | 최근 클라이언트가 트레일링 체크섬을 전송하는 것을 방지합니다       |
| `response_checksum_validation` | `when_required`                | 최근 클라이언트가 응답에서 체크섬을 기대하지 않도록 방지합니다 |

두 체크섬 설정은 최신 클라이언트에 중요합니다. AWS CLI ≥ 2.23 및 최신 `boto3` 버전은 기본적으로 `aws-chunked` 프레이밍을 통해 트레일링 CRC32 체크섬을 전송하며, 게이트웨이는 이를 파싱하지 않습니다. 이 설정들은 클라이언트가 연산이 엄격하게 요구할 때만 체크섬을 전송하도록 지시합니다.

다음은 선택 사항이지만 권장됩니다. 클라이언트 기본값인 8MB를 사용하면 큰 파일이 많은 부분으로 나뉘게 되며, 256MB를 사용하면 업로드당 부분 수가 훨씬 적어지지만 각 부분은 게이트웨이가 효율적으로 처리할 수 있을 만큼 충분히 작게 유지됩니다:

| 설정                  | 값   |
|--------------------------|---------|
| `s3.multipart_threshold` | `256MB` |
| `s3.multipart_chunksize` | `256MB` |

### 예: AWS CLI 프로필

`~/.aws/config`에 프로필을 추가합니다:

```ini
[profile hf]
region = us-east-1
endpoint_url = https://<namespace>.s3.hf.co
s3 =
    addressing_style = path
    multipart_threshold = 256MB
    multipart_chunksize = 256MB
request_checksum_calculation = when_required
response_checksum_validation = when_required
```
참고: 위의 `<namespace>`를 버킷이 저장된 사용자 이름 또는 조직으로 교체하세요.

프로필에 해당하는 자격 증명을 `~/.aws/credentials`에 추가합니다:

```ini
[hf]
aws_access_key_id = HFAK...
aws_secret_access_key = ...
```

이후 해당 프로필을 사용하여 S3 명령을 실행합니다:

```bash
aws --profile hf s3 ls
aws --profile hf s3 mb s3://my-bucket
aws --profile hf s3 cp ./model.safetensors s3://my-bucket/models/model.safetensors
```

## 버킷 처리

AWS S3는 단일하고 평탄하며 전역적으로 고유한 버킷 이름 공간을 사용하며, SDK는 `/`가 없는 단순 문자열로 된 버킷 이름을 기대합니다. Hugging Face 버킷은 `namespace/bucket`으로 식별되며, 여기서 `namespace`는 사용자 이름 또는 조직입니다. 이 추가 계층은 S3 클라이언트와의 불일치를 유발합니다. 많은 클라이언트는 버킷 이름에 `/`를 허용하지 않거나, 이를 잘못 URL-이스케이프합니다. 이를 우회하는 두 가지 방법이 있습니다:

**1. 엔드포인트 URL에 네임스페이스를 포함** (대부분의 경우에 권장). 이렇게 하면 모든 작업이 해당 네임스페이스로 범위가 제한되므로, 클라이언트에 전달하는 버킷 이름은 HF 버킷 이름만 사용하면 됩니다. 자신의 버킷이나 단일 조직의 버킷에는 잘 작동하지만, 네임스페이스를 가로지르는 경우(예: 개인 버킷에서 조직 버킷으로의 서버 사이드 복사)에는 문제가 발생합니다.

각 네임스페이스에는 고유한 엔드포인트 호스트네임이 있습니다. `https://<namespace>.s3.hf.co`:

```bash
aws --endpoint-url https://my-org.s3.hf.co s3api get-object \
  --bucket my-bucket --key some/object.txt ./object.txt
```

네임스페이스는 엔드포인트 경로에 포함할 수도 있으며, 이 경우 `https://s3.hf.co/<namespace>` 형식이 됩니다. 두 형식의 동작은 동일하지만, 호스트네임 형식을 권장합니다. 일부 클라이언트는 경로가 포함된 엔드포인트 URL을 거부하기 때문입니다. [MinIO Go client](https://github.com/minio/minio-go)를 기반으로 구축된 restic, Milvus, Weaviate와 같은 도구가 이에 해당합니다. 네임스페이스 호스트네임은 대소문자를 구분하지 않으므로, `https://my-org.s3.hf.co`도 `My-Org`이라는 이름의 조직에 접근할 수 있습니다.

> [!NOTE]
> 네임스페이스 호스트네임이 있는 경우에도 클라이언트는 path-style addressing을 사용해야 합니다([클라이언트 구성](#configuring-a-client) 참조). 버킷은 자체 서브도메인으로 제공되지 않습니다(`my-bucket.my-org.s3.hf.co`).

**2. 네임스페이스를 버킷으로 취급**하고, 객체 키 앞에 HF 버킷 이름을 붙입니다. 이는 객체 수준 작업(업로드, 다운로드)에는 작동하지만, 버킷 생성 또는 삭제와 같은 버킷 수준 작업에서는 문제가 발생합니다.

```bash
aws --endpoint-url https://s3.hf.co s3api get-object \
  --bucket my-org --key my-bucket/some/object.txt ./object.txt
```

## AWS S3와의 제한 사항 및 차이점

Storage Buckets는 모든 S3 개념을 모델링하지 않으므로, 일부 동작이 다르거나 지원되지 않습니다.

### 오브젝트 다운로드

게이트웨이는 현재 단일 리전으로 운영됩니다. 다운로드 성능을 개선하기 위해 `GetObject`는 바이트를 직접 서빙하는 대신 가장 가까운 Hugging Face CDN 엣지로 HTTP 302 리다이렉트 응답을 반환하는 것이 일반적입니다.

일부 SDK는 S3 엔드포인트의 리다이렉트를 따르지 않으므로, 게이트웨이는 자신을 `aws-cli`, `botocore`(`boto3` 포함) 또는 `aws-sdk-rust`로 식별하는 클라이언트를 감지하고, 해당 클라이언트를 위해 데이터를 자체적으로 프록시합니다. 기타 모든 클라이언트(`rclone`, `s5cmd`, `curl`, AWS Go SDK 등)는 302 응답을 수신하고 이를 네이티브로 따르며, 이를 통해 게이트웨이를 데이터 경로에서 제외하여 더 빠른 다운로드를 가능하게 합니다.

### Object 키 명명

Bucket 객체 키는 S3보다 제한이 더 많습니다. 키는 다음 조건을 **만족하지 않아야** 합니다:

- `/`로 시작하거나 끝납니다
- 연속 슬래시(`//`)를 포함
- `../` 시퀀스를 포함
- `./`로 시작
- `..`로 끝납니다
- 역슬래시(`\`) 또는 널 바이트(`\0`)를 포함

### ListObjects

- `ListObjectsV1`은 지원되지 않습니다 — `ListObjectsV2`를 사용하세요. 일부 클라이언트(예: rclone)는 `ListObjectsV2`만 사용하도록 구성해야 할 수 있습니다.
- 구분자로 `/`만 허용됩니다.

### 기타 API 차이

- **오브젝트 메타데이터**: 임의의 사용자 메타데이터(`x-amz-meta-*`)는 저장되거나 반환되지 않습니다. `Content-Type`은 지원됩니다.
- **지원되지 않는 기능**: ACL, 버킷 정책, 객체 태깅, 객체 버전 관리, 라이프사이클 규칙, 서버 측 암호화(SSE), 버킷 알림은 지원되지 않습니다. 객체는 항상 `STANDARD` 저장 클래스로 보고됩니다. 관련 요청 헤더 및 매개변수는 허용되지만 무시됩니다.
- **CopyObject**: 서버 측 복사는 단일 namespace 내에서만 작동합니다. namespace 간 복사 및 `UploadPartCopy`(기존 객체의 부분을 multipart upload로 복사)은 지원되지 않습니다.
- **조건부 요청**: `If-Match` / `If-None-Match` 사전 조건은 `PutObject` 및 `CopyObject`의 복사 소스에서 적용되지만, `GetObject`에는 적용되지 않습니다.
- **멀티파트 업로드 만료**: 완료되거나 중단되지 않은 진행 중인 멀티파트 업로드는 7일 후 자동으로 만료되고 정리됩니다.

## 예시

일반적인 작업을 위한 실전 레시피입니다. 각 레시피는 위의 [클라이언트 구성](#configuring-a-client)을 기반으로 합니다.

### `boto3`로 읽기 및 쓰기

[`boto3`](https://docs.aws.amazon.com/boto3/latest/)는 위의 [클라이언트 설정](#configuring-a-client)과 함께 게이트웨이에서 작동합니다. `<namespace>`를 사용자 이름 또는 조직으로 대체하세요:

```python
import boto3
from botocore.config import Config

s3 = boto3.client(
    "s3",
    endpoint_url="https://<namespace>.s3.hf.co",
    aws_access_key_id="HFAK...",
    aws_secret_access_key="...",
    config=Config(
        region_name="us-east-1",
        s3={"addressing_style": "path"},
        request_checksum_calculation="when_required",
        response_checksum_validation="when_required",
    ),
)

s3.upload_file("model.safetensors", "my-bucket", "models/model.safetensors")
s3.download_file("my-bucket", "models/model.safetensors", "model.safetensors")
```

### DuckDB로 버킷 쿼리

DuckDB 2.0 이상에서는 `httpfs` 확장 기능이 `hf://buckets/` 경로를 직접 읽을 수 있으며, `hf` 확장 기능을 사용하면 Buckets에 쓸 수도 있습니다. [DuckDB로 쿼리하기](./storage-buckets-access#query-with-duckdb)를 참조하세요.

이전 버전의 DuckDB를 사용하거나, 확장 없이 `COPY ... TO`로 쿼리 결과를 버킷에 다시 기록하려면 대신 S3 게이트웨이를 통해 처리하세요:

```sql
INSTALL httpfs;
LOAD httpfs;

CREATE SECRET hf (
    TYPE s3,
    KEY_ID 'HFAK...',
    SECRET '...',
    ENDPOINT 's3.hf.co/<namespace>',
    URL_STYLE 'path',
    REGION 'us-east-1'
);

SELECT * FROM read_parquet('s3://my-bucket/data.parquet');
```

> [!NOTE]
> `URL_STYLE 'path'`는 필수입니다. 이 값이 없으면 DuckDB는 virtual-hosted-style addressing(`my-bucket.s3.hf.co`)를 사용하며, 게이트웨이는 이를 `my-bucket`이라는 이름의 namespace로 해석하여 요청이 실패합니다.

### `rclone`를 사용하여 데이터를 가져오기

[`rclone`](https://rclone.org/)은 두 개의 S3 호환 스토어 간에 데이터를 복사하는 편리한 방법이며, 기존 AWS S3 버킷(또는 기타 S3 호환 소스)을 Storage Bucket으로 이동하는 데 적합합니다.

> [!TIP]
> 대용량 데이터셋을 이동하는 경우? 소스를 마운트하고 `hf sync`를 실행하면 클라이언트에서 중복을 제거하므로, 일반적으로 rclone보다 적은 바이트를 업로드합니다. [마이그레이션 가이드](./storage-buckets-migration)를 참조하세요.

핵심 아이디어는 두 개의 remote, 즉 소스 버킷과 Hugging Face 게이트웨이를 선언한 뒤 `rclone`이 두 곳 사이에서 객체를 스트리밍하도록 하는 것입니다. 두 remote를 모두 `~/.config/rclone/rclone.conf`에 추가하세요. 첫 번째 remote는 기존 S3 버킷을 가리키며, 소스(여기서는 일반 AWS S3)에 맞게 조정해야 합니다:

```ini
[aws]
type = s3
provider = AWS
access_key_id = AKIA...
secret_access_key = ...
region = us-east-1
```

두 번째는 Hugging Face 게이트웨이를 가리킵니다. 다른 클라이언트와 마찬가지로 엔드포인트를 [namespace](#addressing-buckets)로 범위를 지정하고, `path` 어드레싱을 사용하며, ListObjectsV2를 강제합니다(게이트웨이가 지원하는 유일한 목록 버전). 또한 256M의 파트 크기를 설정합니다. 이는 rclone의 기본값인 5M보다 훨씬 크므로, 큰 파일은 더 적은 파트로 업로드되고, 게이트웨이가 효율적으로 처리할 수 있을 만큼 작으며, rclone의 메모리를 통제할 수 있을 만큼도 작습니다(전송당 4개의 파트를 메모리에 유지합니다):

```ini
[hf]
type = s3
provider = Other
endpoint = https://<namespace>.s3.hf.co
access_key_id = HFAK...
secret_access_key = ...
region = us-east-1
force_path_style = true
list_version = 2
upload_cutoff = 256M
chunk_size = 256M
```

참고: 위의 `<namespace>`를 버킷이 저장된 사용자 이름 또는 조직으로 대체하고, 액세스 토큰에서 생성한 [S3 자격 증명](#generating-s3-credentials)을 사용하세요. 대상 버킷은 해당 네임스페이스 아래에 이미 존재해야 합니다.

이제 소스 버킷을 Storage Bucket으로 복사합니다:

```bash
rclone copy aws:my-source-bucket hf:my-bucket --progress
```

`rclone copy`는 대상에 없거나 변경된 객체만 전송하므로, 중단된 가져오기를 재개하거나 새로운 객체를 가져오기 위해 다시 실행해도 안전합니다. 대상이 소스와 정확히 일치하는 거울이 되도록 — 더 이상 소스에 존재하지 않는 대상의 객체를 삭제하려면 — 대신 `rclone sync`를 사용하세요:

```bash
rclone sync aws:my-source-bucket hf:my-bucket --progress
```

> [!TIP]
> 대용량 가져오기의 경우, 동시성을 높이기 위해 `--transfers`와 `--checkers`를 추가하세요(예: `--transfers 16 --checkers 16`). 이후 `rclone check aws:my-source-bucket hf:my-bucket`를 실행하여 모든 객체가 정상적으로 전송되었는지 확인하세요.

### DVC로 버전 관리

[DVC](https://dvc.org/)는 저장소에는 작은 포인터 파일만 유지하고 실제 데이터를 원격으로 푸시하여 git에서 데이터셋과 모델을 버전 관리합니다. 버킷은 게이트웨이를 통해 DVC 원격으로 작동하므로, 코드와 `.dvc` 포인터는 git에 남아 있고 데이터는 버킷에 저장됩니다. S3 지원이 포함된 DVC를 설치(`pip install 'dvc[s3]'`)한 후, 위의 [클라이언트 설정](#configuring-a-client)을 사용하여 원격 추가:

```bash
dvc remote add -d hf-bucket s3://my-bucket/dvc-store
dvc remote modify hf-bucket endpointurl https://<namespace>.s3.hf.co
dvc remote modify hf-bucket region us-east-1
```

[S3 자격 증명](#generating-s3-credentials)을 환경 변수를 통해 전달하거나, git에 포함되지 않도록 `dvc remote modify --local`를 사용하세요:

```bash
export AWS_ACCESS_KEY_ID=HFAK...
export AWS_SECRET_ACCESS_KEY=...
```

그 후로 `dvc push`와 `dvc pull`을 사용하여 추적, 푸시, 풀을 수행합니다. `dvc push`는 버킷에 업로드하고, 새로 클론한 저장소에서 `dvc pull`을 실행하면 다시 다운로드합니다:

```bash
dvc add data/
git add data.dvc .gitignore .dvc/config && git commit -m "Track data with DVC"
dvc push
```

> [!NOTE]
> `endpointurl`에는 [namespace](#addressing-buckets)를, `s3://` URL에는 버킷 이름만 사용하세요.

