Imgproxy em Docker: URLs Assinadas e Otimização AVIF em Tempo Real

Imgproxy em Docker: URLs Assinadas e Otimização AVIF em Tempo Real

O Problema das Miniaturas Tradicionais: O Disco Fica Cheio Depressa

Em quase todas as plataformas de comércio eletrónico e portais de conteúdos, as imagens representam mais de 70% de todo o tráfego transferido. Os utilizadores e gestores de loja carregam fotos de 12 megapixels tiradas com telemóveis diretamente para o painel de controlo, esperando que o site mostre miniaturas nítidas e leves em computadores, tablets e smartphones.

Tradicionalmente, os programadores tentavam resolver isto gerando miniaturas no momento do carregamento: um script em Node.js ou PHP criava seis ou oito variações estáticas (foto_150x150.jpg, foto_600x400.jpg, foto_1200x800.jpg, e versões em WebP).

Este método tem problemas sérios:

  1. Desperdício Gigantesco de Armazenamento: Se tiveres 20.000 fotos de produtos, passas a ter mais de 200.000 ficheiros no disco, esgotando os inodes do Linux e tornando as cópias de segurança extremamente lentas.
  2. Falta de Flexibilidade de Design: Se o designer alterar as caixas dos produtos de 250px para 280px de largura, tens de criar um script para reprocessar a biblioteca inteira durante horas a fio.
  3. Formatos Ultrapassados: Se quiseres adotar codecs mais modernos como o AVIF, tens de voltar a converter todo o histórico.

A solução profissional é adotar a transformação de media a pedido (on-the-fly). Guardas apenas o ficheiro original em alta resolução, e um motor dedicado—o Imgproxy—redimensiona, corta e converte a imagem exatamente para as dimensões e para o formato que o ecrã do teu visitante necessita.

PIPELINE DE MEDIA EM TEMPO REAL COM IMGPROXY

  • Pedido do Browser: /insecure/resize:fill:400:300/plain/local:///foto.jpg@avif
  • Proxy Nginx / Cache de Borda (Cloudflare)
  • Verifica a Cache: se já existir, devolve o AVIF em 2ms!
  • Se não existir: passa o pedido ao contentor do Imgproxy
  • Contentor Imgproxy (Go + libvips em Docker)
  • Lê a imagem original do disco ou armazenamento S3
  • Aplica corte e redimensionamento por hardware (libvips)
  • Codifica para AVIF ou WebP em ~25 milissegundos
  • Define Cache-Control: public, max-age=31536000, immutable

Esta arquitetura moderna é a base com que construímos websites de alta performance, garantindo que as tuas páginas abrem instantaneamente em qualquer dispositivo móvel.

Como Instalar o Imgproxy em Docker com Aceleração libvips

O Imgproxy foi desenvolvido em Go sobre a biblioteca libvips, a ferramenta de manipulação de imagem de código aberto mais rápida do mercado. É cerca de 5 vezes mais rápida do que o ImageMagick e consome até 85% menos memória RAM.

Aqui tens um ficheiro de configuração pronto para produção com o Docker Compose:

# docker-compose.yml
services:
  imgproxy:
    image: darthsim/imgproxy:v3.24
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      # Chaves Criptográficas Hexadecimais de 32 bytes
      IMGPROXY_KEY: "9f8e7d6c5b4a3928170e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c"
      IMGPROXY_SALT: "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
      
      # Limites de segurança para evitar ataques DoS
      IMGPROXY_CONCURRENCY: 8
      IMGPROXY_MAX_SRC_RESOLUTION: 50
      IMGPROXY_MAX_ANIMATION_FRAMES: 1
      IMGPROXY_TTL: 31536000
      
      # Ajustes de qualidade dos ficheiros
      IMGPROXY_QUALITY: 80
      IMGPROXY_AVIF_QUALITY: 65
      IMGPROXY_WEBP_QUALITY: 75
      
      # Acesso aos ficheiros locais
      IMGPROXY_USE_S3: "false"
      IMGPROXY_LOCAL_FILESYSTEM_ROOT: "/mnt/storage/media"
    volumes:
      - /mnt/storage/media:/mnt/storage/media:ro
    deploy:
      resources:
        limits:
          memory: 2048M
          cpus: '4.0'

Repara como limitamos a concorrência e a resolução máxima da imagem original. Num serviço de alojamento gerido, estas barreiras protegem os teus servidores de picos inesperados de tráfego.

Assinatura Criptográfica HMAC-SHA256: Bloqueia Ataques de DoS

Se deixares o Imgproxy a correr em modo aberto (/insecure/...), qualquer utilizador malicioso pode descobrir o endereço e pedir tamanhos absurdos:

  • /insecure/resize:fill:9999:9999/...
  • /insecure/resize:fill:401:300/...
  • /insecure/resize:fill:402:300/...

Cada pedido destes força o processador a fazer cálculos pesados, deitando a tua máquina abaixo em poucos minutos. Para impedires isto, ativas a validação de assinaturas HMAC-SHA256.

PROCESSO DE ASSINATURA HMAC-SHA256

  1. Caminho a Assinar: /resize:fill:600:400/enlarge:0/plain/local:///banner.jpg@avif
  2. Junção de Bytes: [Salt em Binário] + [Caminho em Binário]
  3. Cálculo HMAC: Hash Criptográfico usando a tua Chave Secreta
  4. Codificação: Assinatura calculada: “qA3v8bZ9_1lM…”
  5. Endereço Seguro: https://media.x078.com/qA3v8bZ9_1lM/resize:fill:600:400/…

Aqui tens o exemplo de código em Node.js para gerares estas URLs no teu servidor:

// src/utils/imgproxySigner.ts
import crypto from 'node:crypto';

const CHAVE = process.env.IMGPROXY_KEY!;
const SALT = process.env.IMGPROXY_SALT!;

export function gerarUrlAssinada(
  caminhoImagem: string,
  largura: number,
  altura: number,
  formato: 'avif' | 'webp' | 'jpg' = 'avif'
): string {
  const modo = 'fill';
  const enlarge = 0;
  
  // Converte o caminho original para base64 seguro
  const urlCodificada = Buffer.from(`local:///${caminhoImagem}`)
    .toString('base64url');
    
  const caminho = `/resize:${modo}:${largura}:${altura}:${enlarge}/${urlCodificada}.${formato}`;
  
  // Calcula o HMAC-SHA256 com a chave secreta
  const hmac = crypto.createHmac('sha256', Buffer.from(CHAVE, 'hex'));
  hmac.update(Buffer.from(SALT, 'hex'));
  hmac.update(Buffer.from(caminho));
  
  const assinatura = hmac.digest().toString('base64url');
  
  return `https://media.x078.com/${assinatura}${caminho}`;
}

Se alguém tentar alterar as dimensões da URL na tentativa de sobrecarregar o servidor, a assinatura deixa de coincidir e o Imgproxy responde de imediato com 403 Forbidden sem gastar recursos da CPU.

Cache Inteligente com Nginx: Processa Uma Vez, Serve Infinitamente

O Imgproxy nunca deve processar a mesma imagem duas vezes. Ao colocares um proxy reverso com o Nginx à frente do contentor, a imagem gerada fica guardada em disco e é entregue de imediato nas visitas seguintes.

# /etc/nginx/conf.d/cache_media.conf

proxy_cache_path /var/cache/nginx/imgproxy 
                 levels=1:2 
                 keys_zone=MEDIA_CACHE:100m 
                 max_size=15g 
                 inactive=60d 
                 use_temp_path=off;

server {
    listen 443 ssl http2;
    server_name media.x078.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_cache MEDIA_CACHE;
        proxy_cache_key "$scheme$request_method$host$request_uri";
        
        # Guarda imagens processadas em cache durante 30 dias
        proxy_cache_valid 200 30d;
        proxy_cache_valid 403 404 1m;
        
        # Proteção contra pedidos simultâneos do mesmo ficheiro
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
        proxy_cache_lock on;
        proxy_cache_lock_timeout 5s;
        
        # Indica aos navegadores que o ficheiro nunca mais muda
        add_header Cache-Control "public, max-age=31536000, immutable";
        add_header X-Cache-Status $upstream_cache_status;
    }
}

Com o parâmetro proxy_cache_lock on, se dez visitantes acederem ao teu site ao mesmo segundo e precisarem da mesma foto de produto, o Nginx deixa apenas o primeiro pedido passar ao Imgproxy. Os restantes nove aguardam uns milissegundos e recebem o ficheiro diretamente da cache. Podes encontrar o código-fonte e documentação deste projeto no GitHub.

Boas Práticas de Engenharia: Qualidade AVIF, Transparências e Marcas de Água

Para tirares o máximo rendimento desta tecnologia seguindo os métodos comprovados na WebXtek, aplica estas recomendações práticas:

  1. Afina a Qualidade do AVIF: Não uses valores de qualidade acima de 70 em ficheiros AVIF. Uma qualidade entre 60 e 65 garante nitidez percetiva perfeita e reduz o tamanho do ficheiro em 60% comparado com JPEG a 80.
  2. Respeita o Canal Alfa: Se converteres logótipos em PNG com fundo transparente para JPEG, o fundo fica preto. O Imgproxy resolve isso convertendo automaticamente para WebP ou AVIF, ou preenchendo o fundo com a cor pretendida através da opção /background:ffffff/.
  3. Aplica Marcas de Água Dinâmicas: Podes proteger fotos originais aplicando marcas de água de forma dinâmica (/watermark:0.7:so:10:10:0.2/) sem teres de alterar o ficheiro original no disco.

Ao combinares o Imgproxy com assinaturas criptográficas e cache estática no Nginx, transformas por completo a velocidade de carregamento dos teus websites estáticos rápidos e garantes uma infraestrutura robusta e segura para os teus clientes.

Na prática, aplicas exatamente estes padrões operacionais em setores exigentes como saas empresarial b2b e especialistas em devops e arquitetura cloud. Quando alinhas a tua estrutura através de websites de alta performance e alojamento gerido para websites e aplicações, transformas boas práticas técnicas numa vantagem competitiva real e mensurável para o teu negócio.

[+] [ INDEX_DIRECTORY ] 13 tópicos ▼
[ SYSTEM.FAQ ]

Perguntas Frequentes

O que é o Imgproxy e porque é superior à geração prévia de miniaturas?

O Imgproxy é um servidor de processamento de imagens ultrarrápido escrito em Go que transforma e converte ficheiros em tempo real com a biblioteca libvips. Em vez de guardares 10 variações estáticas no disco para cada foto enviada, o Imgproxy cria a dimensão e o formato exatos apenas quando o utilizador os pede.

Porque é que as URLs assinadas com HMAC-SHA256 são obrigatórias?

Sem assinaturas criptográficas, qualquer atacante pode criar scripts para pedir milhões de tamanhos arbitrários (por exemplo, 9999x9999 ou variações de pixel a pixel), esgotando a CPU e a memória do teu servidor num ataque DoS. A assinatura garante que o Imgproxy só atende pedidos gerados pelo teu próprio backend.

Qual é a poupança real de largura de banda ao usar AVIF face a JPEG e WebP?

O formato AVIF consegue uma compressão cerca de 50% mais eficiente do que o JPEG clássico e entre 20% a 30% superior ao WebP mantendo a mesma qualidade visual percetível, reduzindo de forma drástica o tempo de Largest Contentful Paint (LCP) em telemóveis.

O Imgproxy pode funcionar atrás de um proxy Nginx ou Cloudflare CDN?

Sim. Em ambientes de produção, o Imgproxy corre atrás do Nginx ou da Cloudflare. A primeira transformação demora cerca de 25 milissegundos e todas as visitas seguintes são servidas diretamente da cache de disco ou da edge com cabeçalhos imutáveis.

> INICIAR_PROJETO

Precisa de um website que transmita confiança, apareça na pesquisa e dê mais força à sua presença digital? Comece a conversa aqui.