Descobrimos um problema, o Cloudflare R2 não permite leitura pública do URL do endpoint S3, mas sim apenas o domínio personalizado ou um domínio r2.dev aleatório.
(Downloads pré-assinados funcionam, apenas o acesso público direto não é suportado.)
Mas o Discourse usa apenas o URL da CDN para imagens incorporadas, e não para downloads diretos, que usam o URL do endpoint S3.
Existe alguma maneira de fazer com que ele use o URL da CDN para todos os arquivos, ou forçar o uso de uma URL pré-assinada?
Relacionado:
A solução alternativa mencionada nesse post funciona, adicionar ?dl=1 corrige isso, porque força o Discourse a usar uma URL S3 pré-assinada.