우선순위/심각도:
S3 호환 백업 스토리지를 사용하는 자체 호스팅 인스턴스의 경우 높음. 아카이브 생성 후 예약된 백업이 실패하기 때문입니다.
플랫폼:
최신 브랜치의 자체 호스팅 Discourse.
관찰 당시 현재 라이브 버전: v2026.4.0-latest
Ruby: 3.4.0
aws-sdk-s3: 1.182.0
설명:
Cloudflare R2로의 백업이 최종 “아카이브 업로드 중…” 단계에서 실패합니다.
데이터베이스 덤프와 로컬 아카이브 생성은 성공적으로 완료되지만, 완료된 백업 아카이브의 멀티파트 업로드가 실패합니다.
실제 결과:
백업이 다음과 같은 오류로 실패합니다:
EXCEPTION: multipart upload failed: undefined method 'downcase' for nil
스택 트레이스에 포함된 내용:
aws-sdk-s3-1.182.0/lib/aws-sdk-s3/multipart_file_uploader.rb
lib/backup_restore/s3_backup_store.rb:48
lib/backup_restore/creator.rb:434
기대되는 결과:
백업 아카이브가 구성된 S3 호환 백업 스토어로 성공적으로 업로드되어야 합니다.
재현 단계:
S3 호환 백업 경로를 사용하여 백업 스토리지를 Cloudflare R2로 구성합니다.
멀티파트 임계값보다 큰 백업 아카이브를 사용합니다.
수동 또는 예약된 백업을 실행합니다.
“아카이브 업로드 중…” 단계에서 실패를 관찰합니다.
관련 구성:
DISCOURSE_BACKUP_LOCATION=s3
DISCOURSE_S3_ENDPOINT=https://.r2.cloudflarestorage.com
DISCOURSE_S3_FORCE_PATH_STYLE=true
DISCOURSE_S3_BACKUP_BUCKET=
AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_REQUIRED
AWS_RESPONSE_CHECKSUM_VALIDATION=WHEN_REQUIRED
관찰된 스택 트레이스 발췌:
algorithm = resp.context.params[:checksum_algorithm]
k = "checksum_#{algorithm.downcase}".to_sym
이것은 멀티파트 업로드 경로에서 checksum_algorithm이 nil임을 시사합니다.
추가 컨텍스트:
Backblaze B2에 대한 유사한 최근 Meta 토론이 있습니다:
I’m facing issues with backing up my Discourse instance, the instance is setup to upload to Backblaze’s B2.
Error log:
Making sure archive does not already exist...
Creating empty archive...
Archiving data dump...
Archiving uploads...
Skipping uploads stored on S3.
Removing tmp '/var/www/discourse/tmp/backups/default/2026-01-16-151337' directory...
Gzipping archive, this may take a while...
Uploading archive...
EXCEPTION: failed to abort multipart upload: SSL_read: unexpected eof while reading…
또한, 1.182.0 이후의 aws-sdk-s3 변경 로그 항목이 관련 있어 보입니다:
1.201.0: when_required 모드에서 request_checksum_calculation을 준수하도록 멀티파트 업로드 수정
1.210.2: PutObject 및 UploadPart 작업에서 사용자 정의 엔드포인트 또는 엔드포인트 제공자를 사용할 때 헤더 요청 체크섬으로 폴백
Discourse main은 현재 여전히 aws-sdk-s3를 1.182.0으로 고정하고 있는 것으로 보입니다:
https://raw.githubusercontent.com/discourse/discourse/main/Gemfile.lock
pfaffman
(Jay Pfaffman)
4월 2, 2026, 2:49오후
2
오래전에 확인한 건 아니지만, 예전에 이렇게 처리했던 적이 있습니다:
But I did for a site that’s using Backblaze. I created a template I put in /root/aws-revert-template.yml with this:
# This template reverts aws-sdk-s3 to a version that works with backblaze
params:
home: /var/www/discourse
hooks:
after_bundle_exec:
- exec:
cd: $home
cmd:
- bundle config set frozen false
- "sed -i 's/gem \"aws-sdk-s3\", require: false/gem \"aws-sdk-s3\", \"1.177.0\", require: false/' Gemfile"
- bundle update aws-sdk-s3
…
이들은 이 문제를 #contribute:bug로 간주하지 않습니다. 왜냐하면 전 세계의 모든 S3 호환(이것도 좀 애매한) 서비스를 지원한다고 주장하지 않기 때문입니다.
구체적으로 어떤 사이트들을 위해 이렇게 했는지 기억이 나지 않지만, 최근에 이 부분에 대해 변경한 것이 없었던 것 같아서 이것이 여전히 "최선"의 우회 방법이라고 생각합니다.
AWS가 새로운 라이브러리를 출시했을 때 다른 서비스 제공업체들의 서비스들을 망가뜨렸다는 내용으로 다른 주제들 몇 개가 있었던 것 같습니다.
2개의 좋아요
감사합니다. 저에게는 이 방법으로 문제가 해결되었습니다.
app.yml에서 after_bundle_exec를 통해 워크어라운드를 직접 적용하고, aws-sdk-s3를 1.177.0으로, aws-sdk-core를 3.215로 고정시킨 후 컨테이너를 다시 빌드했습니다. 이후 Cloudflare R2로의 수동 백업이 다시 성공했으며, 이전에 실패하던 브라우저 업로드도 다시 정상 작동하기 시작했습니다.
제 경우에는 aws-sdk-s3 1.182.0에서 multipart upload failed: undefined method 'downcase' for nil 오류로 나타났습니다.
워크어라운드 감사합니다.
1개의 좋아요
amiantos
(Brad Root)
4월 4, 2026, 7:30오전
4
수정… 이 우회 방법이 저한테도 효과가 있었어요. 다만 기존 훅 블록에 추가하는 대신 별도의 hooks: 블록에 넣어야 했어요. 제가 너무 멍청했네요.
1개의 좋아요