Seu próprio armazenamento + CDN
Conecte seu próprio armazenamento de objetos e sua própria CDN nos planos de API Velocity e Momentum: configuração por provedor, permissões mínimas, a verificação da conexão e o que acontece quando você muda de modo.
Disponível em: planos de API Velocity e Momentum. Não disponível no Ignite (ele não tem CDN), no sandbox de desenvolvedor (os arquivos do sandbox são temporários) nem nos planos WordPress (eles usam a CDN gerenciada do smallPict).
Em resumo: No modo BYO, o smallPict grava seus originais e as imagens otimizadas no seu bucket, e a sua CDN os entrega. Armazenamento e CDN são sempre conectados juntos: não é possível trazer um sem o outro.
O que é o BYO
O Velocity e o Momentum têm dois modos de entrega. Você escolhe um em Painel → CDN e armazenamento.
- Gerenciado (o padrão): o smallPict guarda seus originais no armazenamento criptografado dele (movidos para o arquivo de longo prazo após 90 dias) e entrega as imagens otimizadas a partir de
cdn.smallpict.app. Nada para configurar. - Use seu próprio armazenamento + CDN (BYO): você conecta um bucket compatível com S3 na sua própria conta e uma CDN na sua própria conta. Cada nova tarefa grava o original e o arquivo otimizado no seu bucket, e a API retorna URLs no domínio da sua CDN.
A regra de conexão conjunta existe porque o smallPict precisa conseguir fazer as duas metades da entrega: gravar arquivos e limpar cópias desatualizadas do cache. Um bucket sem CDN deixaria as purgas de cache sem destino; uma CDN sem bucket não teria nada para entregar.
Gerenciado vs. BYO
| Gerenciado (padrão) | Use seu próprio armazenamento + CDN | |
|---|---|---|
| Originais | Armazenamento criptografado do smallPict | originals/<job_id>/<file> no seu bucket |
| Arquivos otimizados | Entregues a partir de cdn.smallpict.app | optimized/<job_id>.<ext> no seu bucket, entregues a partir do domínio da sua CDN |
| Cota de armazenamento | Velocity 50 GB, Momentum 100 GB | Não é contabilizada. Você paga ao seu provedor de armazenamento. |
| Largura de banda da CDN | Velocity 30 GB/mês, Momentum 200 GB/mês | Não é contabilizada. Você paga ao seu provedor de CDN. |
| Transformações | Contam para o seu plano | Contam para o seu plano |
| Cópia mantida pelo smallPict | Sim, enquanto sua conta estiver ativa | Nenhuma. Apenas o upload temporário de processamento, excluído em até 24 horas. |
| Purga de cache | Automática | Automática, pela API da sua CDN |
| Desempenho, domínio e custos da CDN | smallPict | Você. O smallPict não é responsável pelo desempenho, pelos domínios nem pelas faturas da sua CDN. |
Provedores compatíveis
Armazenamento (disponível hoje): Amazon S3, Cloudflare R2, Google Cloud Storage (interoperabilidade com S3), Alibaba Cloud OSS, Tencent Cloud COS, DigitalOcean Spaces, SumoPod Storage, MinIO e qualquer outro serviço compatível com S3 por meio de um endpoint personalizado (por exemplo Hetzner, Vultr ou Wasabi).
CDN (disponível hoje): Cloudflare e Amazon CloudFront.
Planejados: Azure Blob Storage e outras CDNs. Você pode pedir acesso antecipado na página Provedores de nuvem.
Antes de começar
- Você está no API Velocity ou Momentum e conectado como administrador da conta.
- Você tem um bucket e uma CDN que entrega os arquivos desse bucket por HTTPS.
- O endpoint de armazenamento é acessível pela internet via HTTPS. Endpoints privados, internos e HTTP simples são rejeitados.
- Você criou chaves restritas para o smallPict (veja Permissões mínimas abaixo). Não use as chaves root ou de administrador da sua conta.
Depois, abra Painel → CDN e armazenamento, escolha Use seu próprio armazenamento + CDN, preencha as duas partes e selecione Salvar armazenamento + CDN. O smallPict executa a verificação da conexão (descrita abaixo) e só muda você para o BYO se ela for aprovada.
Guias de configuração
A. Amazon S3 + Amazon CloudFront
- Crie o bucket na região desejada, por exemplo
my-imagesemap-southeast-1. Mantenha o Block Public Access ativado. - Crie uma distribuição do CloudFront com o bucket como origem. Use Origin access control (OAC) para que o CloudFront possa ler o bucket enquanto ele continua privado, e aplique a política de bucket que o CloudFront oferece.
- Opcional: seu próprio domínio. Adicione à distribuição um nome de domínio alternativo (por exemplo
images.example.com) e um certificado, e aponte um registro DNS para a distribuição. - Crie um usuário IAM (ou função) para o armazenamento com esta política:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::my-images/*" } ]}- Crie um usuário IAM para o CloudFront (pode ser o mesmo usuário) com esta política.
cloudfront:GetDistributioné opcional; com ela, o smallPict consegue detectar o domínio da distribuição quando você deixa o domínio da CDN em branco.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "cloudfront:CreateInvalidation", "cloudfront:GetDistribution" ], "Resource": "arn:aws:cloudfront::123456789012:distribution/E2QWRUHAPOMQZL" } ]}- No painel:
- Provedor de armazenamento Amazon S3, bucket
my-images, regiãoap-southeast-1, endpoint em branco (é usado o endpoint padrão da região) e o access key ID e o secret do armazenamento. - CDN Amazon CloudFront, o Distribution ID (por exemplo
E2QWRUHAPOMQZL), o access key ID e o secret do CloudFront e, opcionalmente, o domínio da CDN (https://images.example.com). Deixe o domínio em branco para usar o domínio*.cloudfront.netda própria distribuição.
- Provedor de armazenamento Amazon S3, bucket
B. Cloudflare R2 + Cloudflare
- Crie um bucket R2, por exemplo
my-images. - Conecte um domínio personalizado ao bucket (R2 → seu bucket → Settings → Custom Domains), por exemplo
images.example.com, em uma zona da mesma conta Cloudflare. As requisições para esse domínio passam pelo cache da Cloudflare. Não use a URL de desenvolvimentor2.devem produção. - Crie um token de API do R2 (R2 → Manage API tokens) com Object Read & Write, restrito apenas a este bucket. Copie o Access Key ID e a Secret Access Key exibidos.
- Crie um token de API da Cloudflare (My Profile → API Tokens) para a zona com Zone → Cache Purge → Purge. Zone → Zone → Read é opcional.
- No painel:
- Provedor de armazenamento Cloudflare R2, bucket
my-images, endpointhttps://<account_id>.r2.cloudflarestorage.com(mostrado nos detalhes da API S3 do seu bucket), regiãoautoe o Access Key ID e a Secret Access Key do R2. - CDN Cloudflare, o Zone ID (página Overview do domínio, seção API), o token de API e o domínio da CDN
https://images.example.com.
- Provedor de armazenamento Cloudflare R2, bucket
C. Google Cloud Storage + Cloudflare
O Google Cloud Storage é conectado pela XML API compatível com S3, com chaves HMAC.
- Crie o bucket, por exemplo
my-images. - Crie uma conta de serviço e conceda a ela Storage Object User (
roles/storage.objectUser) apenas neste bucket. - Crie uma chave HMAC para a conta de serviço: Cloud Storage → Settings → Interoperability → Create a key for a service account. Copie o access ID e o secret.
- Torne os arquivos otimizados legíveis pela sua CDN. A Cloudflare busca os arquivos no Cloud Storage por HTTPS, então os objetos em
optimized/precisam ter leitura pública. Com o acesso uniforme no nível do bucket, conceder aallUserso papel Storage Object Viewer torna o bucket inteiro legível, incluindooriginals/. Se seus originais precisam continuar privados, coloque uma camada de autenticação na frente (por exemplo um Cloudflare Worker que assina as requisições ao bucket). - Aponte um registro DNS com proxy da Cloudflare para o Cloud Storage, por exemplo
images.example.com. Dê ao bucket o mesmo nome do hostname e use um CNAME com proxy parac.storage.googleapis.com, ou use uma Cloudflare Origin Rule que envie as requisições parastorage.googleapis.comcom o nome do bucket no início do caminho. - Crie um token de API da Cloudflare para a zona com Zone → Cache Purge → Purge (Zone → Zone → Read opcional).
- No painel: provedor de armazenamento Google Cloud Storage, bucket, endpoint
https://storage.googleapis.com, regiãoauto, o access ID e o secret HMAC; CDN Cloudflare, Zone ID, token de API e domínio da CDNhttps://images.example.com.
D. MinIO ou qualquer armazenamento compatível com S3 + Cloudflare
Isto cobre o MinIO e serviços compatíveis com S3 como Hetzner, Wasabi, Vultr, SumoPod, Alibaba Cloud OSS, Tencent Cloud COS e DigitalOcean Spaces.
| Provedor | Escolha no painel | Endpoint | Observações |
|---|---|---|---|
| MinIO | MinIO | Seu servidor, ex.: https://minio.example.com | Requisições path-style ativadas. O servidor precisa ser acessível pela internet via HTTPS. |
| Hetzner Object Storage | S3 compatível personalizado | https://<location>.your-objectstorage.com | |
| Wasabi | S3 compatível personalizado | https://s3.<region>.wasabisys.com | |
| Vultr Object Storage | S3 compatível personalizado | https://<region>.vultrobjects.com | |
| SumoPod Storage | SumoPod Storage | No painel de armazenamento do SumoPod | Path-style ativado por padrão. |
| Alibaba Cloud OSS | Alibaba Cloud OSS | https://oss-<region>.aliyuncs.com | Somente estilo virtual-hosted. |
| Tencent Cloud COS | Tencent Cloud COS | https://cos.<region>.myqcloud.com | O nome do bucket inclui seu APPID, ex.: my-images-1250000000. |
| DigitalOcean Spaces | DigitalOcean Spaces | https://<region>.digitaloceanspaces.com |
- Crie o bucket e uma chave limitada a esse bucket com put, get e delete nos objetos (veja Permissões mínimas abaixo).
- Torne
optimized/legível pela sua CDN, por exemplo com uma política de bucket que permitas3:GetObjectanônimo apenas emoptimized/*. No MinIO:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": [ "*" ] }, "Action": [ "s3:GetObject" ], "Resource": [ "arn:aws:s3:::my-images/optimized/*" ] } ]}- Coloque a Cloudflare na frente do bucket: um registro DNS com proxy para
images.example.comque aponte para o host público do bucket. Se o provedor exigir o próprio hostname na requisição, adicione uma Cloudflare Origin Rule que reescreva o cabeçalho Host (e, para hosts path-style, adicione o nome do bucket ao caminho). - Crie um token de API da Cloudflare para a zona com Zone → Cache Purge → Purge (Zone → Zone → Read opcional).
- No painel: escolha o provedor na tabela, informe o bucket, o endpoint, a região (
autose o provedor não tiver uma) e as chaves; ative as requisições path-style onde a tabela indicar; depois, CDN Cloudflare, Zone ID, token de API e domínio da CDN.
Permissões mínimas
Dê ao smallPict chaves que só possam fazer o necessário, em um único bucket.
| Provedor | Permissões |
|---|---|
| Amazon S3 | s3:PutObject, s3:GetObject, s3:DeleteObject em arn:aws:s3:::<bucket>/* |
| Amazon CloudFront | cloudfront:CreateInvalidation na distribuição; opcionalmente cloudfront:GetDistribution para que o domínio possa ser detectado |
| Cloudflare R2 | Token de API do R2 com Object Read & Write, restrito ao bucket |
| Cloudflare (CDN) | Token de API da zona com Zone → Cache Purge → Purge; opcionalmente Zone → Zone → Read |
| Google Cloud Storage | Chave HMAC de uma conta de serviço com roles/storage.objectUser no bucket |
| Alibaba Cloud OSS | Usuário RAM com oss:PutObject, oss:GetObject, oss:DeleteObject no bucket |
| Tencent Cloud COS | Subusuário CAM com cos:PutObject, cos:GetObject, cos:DeleteObject no bucket (o nome do bucket inclui o APPID) |
| DigitalOcean Spaces | Chave de acesso do Spaces limitada ao bucket, com leitura, gravação e exclusão |
| MinIO / S3 compatível personalizado | Put, get e delete em <bucket>/*; o endpoint precisa ser HTTPS público |
A verificação da conexão
Sempre que você salva (e quando seleciona Verificar novamente), o smallPict verifica a conexão inteira antes de usá-la:
- Armazenamento: grava um pequeno arquivo de teste em
.smallpict-probe/no seu bucket, lê o arquivo de volta e o exclui. - Cloudflare: envia uma purga de teste de uma única URL para a sua zona.
- CloudFront: cria uma invalidação de teste para um caminho
/.smallpict-probe/.... Ela conta para os seus caminhos de invalidação do CloudFront no mês.
Se alguma etapa falhar, nada é mudado. O painel mostra o motivo ao lado do campo correspondente, por exemplo o nome do bucket ou o token de API. A verificação da conexão é limitada a 5 tentativas por minuto.
Acesso da sua CDN ao bucket
optimized/precisa ser legível pela sua CDN: leitura pública nesse prefixo ou acesso de origem da CDN a um bucket privado (CloudFront origin access control ou um domínio personalizado do R2).originals/pode continuar privado. Sua CDN nunca precisa dele.- CORS só é necessário se os navegadores buscarem as imagens entre origens a partir de JavaScript (por exemplo
fetch()ou um canvas). Tags<img>comuns não precisam dele. Se você precisar, permitaGETeHEADa partir da origem do seu site.
Estrutura de objetos e URLs
| O quê | Chave no seu bucket | URL |
|---|---|---|
| Original | originals/<job_id>/<file> | Não é entregue |
| Arquivo otimizado | optimized/<job_id>.<ext> | <cdn_domain>/optimized/<job_id>.<ext> |
O domínio da CDN pode incluir um prefixo de caminho, por exemplo https://example.com/images; nesse caso a URL fica https://example.com/images/optimized/<job_id>.<ext>.
Cabeçalhos de cache
Os arquivos otimizados são gravados com Cache-Control: public, max-age=31536000, immutable. Cada tarefa recebe uma chave única, então um novo resultado sempre tem uma nova URL e a purga raramente é necessária. Não deixe que as regras de cache da sua CDN substituam este cabeçalho por um tempo menor.
Purga de cache
- As requisições de purga feitas pela API (
POST /v1/purge) vão para a sua CDN, em lotes. - Na Cloudflare, os arquivos são purgados por URL. "Purgar tudo" purga apenas o seu host de entrega e o prefixo de caminho, não a zona inteira.
- No CloudFront, os arquivos são purgados com invalidações. "Purgar tudo" cria uma invalidação
/*. Os caminhos de invalidação acima da cota gratuita mensal do CloudFront são cobrados pela AWS na sua conta.
Mudança de modo
Mudar de modo não move os arquivos existentes. Os arquivos já entregues mantêm as URLs atuais; só as novas tarefas usam o novo modo.
- Gerenciado → BYO: as novas tarefas vão para o seu bucket e são entregues pela sua CDN. Os arquivos que já estão em
cdn.smallpict.appcontinuam lá. - BYO → gerenciado: as novas tarefas voltam a usar armazenamento e CDN gerenciados. Suas configurações e chaves de BYO continuam salvas, mas sem uso, para que você possa voltar sem digitá-las de novo, até selecionar Desconectar.
- Desconectar: exclui as chaves e configurações de BYO salvas e volta você para o modo gerenciado. Os arquivos no seu bucket não são alterados.
Quando algo falha
- Se o smallPict não conseguir gravar no seu bucket, ele tenta novamente e depois marca a tarefa como falha, com um motivo que você pode ler na resposta da API.
- O painel mostra o último erro e quando ele aconteceu, com um botão Verificar novamente.
- Você recebe um e-mail por incidente, não um por tarefa com falha.
- O smallPict nunca recorre ao armazenamento gerenciado. Seus arquivos nunca são guardados em um lugar que você não escolheu.
Segurança
- As chaves ficam guardadas em um cofre de segredos criptografado. Elas nunca são exibidas novamente, nunca são retornadas pela API e nunca são gravadas em logs.
- Para trocar uma chave, digite a nova e salve; a verificação da conexão é executada com a nova chave. Deixe um campo de chave em branco para manter a chave salva.
- Os endpoints de armazenamento e de CDN precisam usar HTTPS. Endpoints que resolvem para endereços privados, de loopback, link-local ou outros endereços internos são rejeitados.
- Use chaves separadas e restritas para o smallPict e revogue-as no console do seu provedor se deixar de usar o BYO.