Skip to content
Voltar ao blog
Segurança

Como criar um arquivo .htpasswd: guia de HTTP Basic Auth

Crie um arquivo .htpasswd com bcrypt ou apr1, configure HTTP Basic Auth no Apache, nginx, Docker e Kubernetes e proteja o acesso. Guia prático de 2026.

11 min de leitura

Como criar um arquivo .htpasswd: guia de HTTP Basic Auth

Um arquivo .htpasswd é o repositório de credenciais do lado do servidor para a HTTP Basic Authentication: um arquivo de texto puro em que cada linha é um par username:hash. Para criar um arquivo .htpasswd, você gera essa linha com o hash e a salva em algum lugar que seu servidor web consiga ler. Há três maneiras de fazer isso:

  • O comando htpasswd (do apache2-utils / httpd-tools) — a ferramenta canônica.
  • openssl passwd — já vem instalado em praticamente todo lugar, sem pacote extra.
  • No seu navegador — use o gerador de htpasswd para criar uma entrada localmente, sem instalar nada e sem enviar nada pela rede.

Este guia vai além do comando de uma linha. Veremos como o handshake do Basic Auth funciona de fato, como criar o arquivo de três formas, qual dos cinco formatos de hash escolher, como integrá-lo a Apache, nginx, Docker, Kubernetes, Caddy e Traefik, e como blindar tudo para você não publicar um arquivo de credenciais que qualquer um pode baixar.

O que é um arquivo .htpasswd?

Cada linha de um arquivo .htpasswd guarda as credenciais de um usuário como um par separado por dois-pontos. O nome de usuário é armazenado como está; a senha é armazenada apenas como um hash de mão única, então o texto puro nunca é gravado em disco. A anatomia de uma única linha bcrypt fica assim:

admin    :    $2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
│             │
└─ username   └─ hash (algorithm prefix $2y$ + cost + salt + digest)

Primeiro vem o nome de usuário, depois um único :, depois o hash. Um nome de usuário pode ter até 255 bytes e nunca pode conter dois-pontos, já que o dois-pontos é o separador de campos. O hash carrega seu próprio marcador de algoritmo como prefixo ($2y$ para bcrypt, $apr1$ para o MD5 do Apache, {SHA} para SHA-1), de modo que o servidor sabe como verificá-lo sem nenhuma configuração extra.

Para vários usuários, você adiciona uma linha por usuário:

admin:$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
alice:$2y$10$3bQ8xY7tLp2mZ0xW5cR4fO9vK1jH6sD2nG8aQ5wE3rT7uI4oP1cm
bob:$apr1$mZ0xW5cR$4fK1jH6sD2nG8aQ5wE3rT2

Os algoritmos podem ser misturados no mesmo arquivo. O servidor lê cada linha, detecta o formato pelo prefixo e verifica usando o que foi empregado. Aqui dois usuários bcrypt e um usuário apr1 convivem sem problema.

.htpasswd vs .htaccess

Esses dois são confundidos o tempo todo porque andam juntos no Apache, mas fazem trabalhos diferentes. O .htaccess é o arquivo de configuração por diretório do Apache. Ele contém diretivas — inclusive as que ativam o Basic Auth e apontam para o seu repositório de credenciais. O .htpasswd é o banco de credenciais — apenas as linhas username:hash, sem nenhuma configuração.

Em resumo: o .htaccess decide que um diretório exige login e onde encontrar a lista de usuários; o .htpasswd é essa lista de usuários. O nginx não usa .htaccess de jeito nenhum — sua configuração de Basic Auth fica no bloco server ou location da configuração principal, mas ele lê o mesmo formato de credenciais .htpasswd.

Como funciona a HTTP Basic Authentication

A HTTP Basic Authentication é um handshake de desafio-resposta embutido na especificação do HTTP. Entender as três etapas torna óbvio cada passo posterior de diagnóstico:

  1. O cliente requisita um recurso protegido sem credenciais.
  2. O servidor responde 401 Unauthorized e inclui um cabeçalho WWW-Authenticate: Basic realm="..." — esse é o desafio.
  3. O cliente repete a requisição com um cabeçalho Authorization: Basic <base64(user:password)>. Se as credenciais coincidirem com uma linha do arquivo .htpasswd, o servidor devolve o recurso.

É esse o protocolo inteiro. Não há formulário de login, nem cookie de sessão, nem token. Toda requisição seguinte carrega o mesmo cabeçalho.

O desafio 401 / WWW-Authenticate

O cabeçalho WWW-Authenticate faz duas coisas. Seu token Basic informa ao cliente qual esquema usar, e sua string realm rotula o espaço de proteção. Os navegadores mostram o texto do realm na caixa de diálogo de login (“O site diz: …”) e o usam como chave de cache: as credenciais informadas para um realm são reutilizadas em outras URLs do mesmo realm, então o usuário não é solicitado de novo a cada página.

Aqui está a troca crua, capturada com curl -i:

$ curl -i https://example.com/admin/
HTTP/2 401
www-authenticate: Basic realm="Restricted Area"

$ curl -i -u admin:s3cret https://example.com/admin/
HTTP/2 200

O cabeçalho Authorization: Basic

A credencial que o cliente envia é base64(username:password). E aqui está o detalhe de segurança que pega muita gente: base64 é codificação, não criptografia. Qualquer pessoa reverte isso, então a credencial trafega, na prática, em texto puro. Você mesmo pode ver a ida e volta:

# Encode the credential the way a browser does
printf 'admin:s3cret' | base64
# → YWRtaW46czNjcmV0

# Anyone who captures the header can decode it instantly
printf 'YWRtaW46czNjcmV0' | base64 -d
# → admin:s3cret

Essa reversibilidade é o motivo de o Basic Auth ter de rodar sobre HTTPS — sem TLS, a senha fica legível para qualquer um no caminho da rede. Se você quiser construir ou inspecionar esse cabeçalho à mão, o codificador/decodificador Base64 faz a mesma transformação de user:password no navegador.

Como criar um arquivo .htpasswd

Há três formas práticas de criar o arquivo. Escolha com base no que está instalado e onde você quer que a senha fique.

Usando o comando htpasswd

O binário htpasswd vem no pacote de utilitários do Apache. Instale-o primeiro:

# Debian / Ubuntu
sudo apt install apache2-utils

# RHEL / CentOS / Fedora
sudo yum install httpd-tools

Crie o arquivo e seu primeiro usuário. A flag -c significa create, e ela vai sobrescrever um arquivo existente — use-a apenas na primeira vez:

htpasswd -c /etc/nginx/.htpasswd admin
# prompts twice for the password, then writes the file

Para adicionar mais usuários, tire o -c para anexar em vez de apagar tudo:

htpasswd /etc/nginx/.htpasswd alice

Para forçar o bcrypt em vez do padrão da plataforma, adicione -B. Para imprimir a entrada na saída padrão sem tocar em nenhum arquivo — útil para encadear em uma configuração ou em um Dockerfile — combine -b (senha na linha de comando) e -n (sem arquivo):

htpasswd -Bbn admin 's3cret'
# → admin:$2y$10$N9qo8uLOickgx2ZMRZoMye...

As flags que você realmente vai usar:

FlagSignificado
-cCria um novo arquivo (sobrescreve se já existir) — apenas o primeiro usuário
-BUsa bcrypt
-bRecebe a senha como argumento de linha de comando (sem prompt)
-nImprime na saída padrão em vez de gravar um arquivo
-DRemove o usuário indicado do arquivo

Uma ressalva sobre o -b: a senha acaba no histórico do seu shell. Para credenciais de produção pontuais, prefira a forma com prompt ou a opção do navegador abaixo.

Sem o apache2-utils — usando o OpenSSL

Não tem o binário htpasswd? O OpenSSL está em praticamente todo sistema e consegue produzir um hash apr1 diretamente. Envolva-o em printf para montar uma linha completa:

printf "admin:$(openssl passwd -apr1 's3cret')\n" >> /etc/nginx/.htpasswd
# admin:$apr1$k3l4Hj9.$qN8vY7tLp2mZ0xW5cR4f.

O formato apr1 é portável tanto no Apache quanto no nginx, o que faz dele a rota com menos dependências em uma máquina enxuta.

No navegador — sem instalar, sem vazar

Se você não quer instalar um pacote, ou prefere não digitar uma senha de produção num shell onde ela cai no ~/.bash_history, gere a entrada no lado do cliente. O gerador de htpasswd calcula hashes bcrypt, apr1 e SHA-1 inteiramente no seu navegador, entrega uma linha user:hash pronta para colar mais um bloco de configuração de servidor correspondente, e nunca transmite nada. Já que você está lá, crie uma senha forte e única com o gerador de senhas aleatórias em vez de reaproveitar uma.

Formatos de senha do htpasswd comparados

O comando htpasswd pode emitir cinco formatos, e eles não são equivalentes. Esta tabela é a referência rápida para escolher um:

FormatoPrefixoCom saltForçaUse para
bcrypt$2y$SimMais forteApache, Docker Registry, Caddy, Traefik
apr1 (MD5 do Apache)$apr1$SimModeradanginx (portável, padrão seguro)
SHA-1{SHA}NãoFracaApenas compatibilidade legada
crypt (DES)(nenhum)Sim (2 caracteres)Muito fracaNão use
plain(nenhum)NãoNenhumaApenas testes locais

Algumas observações que não cabem numa célula de tabela. O bcrypt usa um salt aleatório de 16 bytes e um fator de custo adaptativo (padrão 10, recomendação moderna 12), de modo que senhas idênticas produzem hashes diferentes e o fator de trabalho acompanha o hardware. Tem um detalhe peculiar: o bcrypt trunca a senha em 72 bytes, e qualquer coisa além disso é ignorada sem aviso. O apr1 roda 1.000 rodadas de MD5 com salt. É bem mais fraco que o bcrypt, mas tanto o Apache quanto o nginx o implementam nativamente, e é por isso que ele acaba sendo a escolha portável. O SHA-1 não usa salt, então senhas idênticas geram digests idênticos e tabelas rainbow se aplicam; guarde-o só para sistemas legados. O crypt e o plain existem por razões históricas e de teste, e nenhum dos dois tem lugar em produção.

Os prefixos $2a$ / $2b$ / $2y$

Você verá hashes bcrypt começando com $2a$, $2b$ ou $2y$. São o mesmo algoritmo e produzem hashes equivalentes e intercambiáveis; as letras de versão são resquícios de correções históricas de bugs na forma como certas bibliotecas tratavam caracteres de bit alto e o comprimento das strings. O htpasswd do Apache emite $2y$, e Caddy, Traefik e Docker Registry todos o verificam corretamente.

Se você quiser a comparação mais aprofundada do bcrypt frente a alternativas modernas, o guia bcrypt vs Argon2 vs scrypt explica como esses algoritmos de hash de senha diferem em custo, dureza de memória e modelo de ameaça.

Configurando o Basic Auth no seu servidor

Um arquivo de credenciais não faz nada sozinho: você precisa dizer ao servidor que ele é obrigatório. Aqui estão seis plataformas.

Apache (.htaccess)

Coloque isto em um arquivo .htaccess no diretório que você quer proteger (ou em um bloco <Directory> no seu vhost):

AuthType Basic
AuthName "Restricted Area"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user

AuthName é a string de realm que o navegador mostra; AuthUserFile é o caminho absoluto até o seu arquivo de credenciais; Require valid-user aceita qualquer usuário listado nele.

nginx (auth_basic)

O nginx coloca a configuração em um bloco location ou server — não existe .htaccess:

location /admin/ {
    auth_basic           "Restricted Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

Recarregue com nginx -s reload. Use o formato apr1 aqui. O nginx delega a verificação do bcrypt ao crypt() do sistema, que falha em muitas builds (mais sobre isso na seção de diagnóstico), enquanto o apr1 é verificado internamente em toda plataforma.

Docker Registry e ingress-nginx do Kubernetes

O backend htpasswd de um Docker Registry privado aceita apenas bcrypt. Gere a entrada, monte-a e aponte o registry para ela:

# Generate a bcrypt entry into a file
htpasswd -Bbn admin 's3cret' > auth/htpasswd

# Run the registry with that file
docker run -d -p 5000:5000 \
  -v "$(pwd)/auth:/auth" \
  -e REGISTRY_AUTH=htpasswd \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  registry:2

Para o ingress-nginx do Kubernetes, armazene o arquivo como um Secret e referencie-o com anotações:

kubectl create secret generic basic-auth --from-file=auth=./auth/htpasswd
metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"

Repare que a chave do Secret precisa se chamar auth — o ingress-nginx procura exatamente por essa chave.

Caddy e Traefik

Ambos esperam hashes bcrypt. O Caddy usa a diretiva basic_auth (cole o hash bcrypt, não o texto puro):

example.com {
    basic_auth /admin/* {
        admin $2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
    }
}

O Traefik usa um middleware basicauth, com pares user:bcrypt-hash (escape qualquer $ conforme o formato da sua configuração):

http:
  middlewares:
    admin-auth:
      basicAuth:
        users:
          - "admin:$2y$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"

Depois que um endpoint está protegido, verifique se funciona pela linha de comando. O construtor de comandos cURL monta a requisição -u user:pass para você, de modo que você consiga confirmar tanto o 401 quanto o 200 autenticado.

Boas práticas de segurança

O Basic Auth é simples, e isso torna fácil identificar as poucas formas de usá-lo mal.

  • Sempre sirva por HTTPS. A credencial é base64 reversível, então o HTTP puro expõe a senha na rede. Faça a terminação do TLS na frente de qualquer endpoint protegido, sem exceções.
  • Guarde o arquivo fora da raiz web. Se o .htpasswd ficar em um diretório servido, uma má configuração pode deixar que alguém o baixe. Mantenha-o em algum lugar como /etc/nginx/.htpasswd, defina chmod 640 e faça com que pertença ao usuário do servidor web (www-data, nginx), para que o servidor consiga lê-lo e as outras contas não.
  • Use senhas fortes e únicas. Cada conta deve receber sua própria senha de alta entropia do gerador de senhas aleatórias, nunca reutilizada. Se você quiser entender o que “forte o suficiente” significa em bits, o explicador de entropia de senhas detalha a matemática.
  • Conheça os limites. O Basic Auth não tem logout e não tem sessão: o navegador faz cache da credencial por realm até você fechá-lo, e ela é reenviada a cada requisição. Para um checklist mais amplo sobre hashing, cabeçalhos e validação, veja nossas boas práticas de segurança web.

Resolvendo erros comuns

nginx: crypt_r() failed (22: Invalid argument)

Esta é a falha de Basic Auth no nginx mais comum de todas, e ela sempre significa a mesma coisa: o nginx tentou verificar um hash bcrypt ($2y$) numa libc que não inclui o esquema Blowfish — tipicamente o musl do Alpine ou uma glibc mais antiga. A correção é regerar a entrada como apr1, que o nginx verifica internamente em qualquer plataforma:

printf "admin:$(openssl passwd -apr1 's3cret')\n" > /etc/nginx/.htpasswd
nginx -s reload

Trocar por uma imagem base cuja libc suporte bcrypt também funciona, mas o apr1 é a solução mais simples e portável.

401 mesmo com a senha certa

Quando você tem certeza de que a senha está correta mas ainda recebe um 401, percorra este checklist em ordem:

  1. Caminho do arquivo. Confirme que o AuthUserFile / auth_basic_user_file aponta para o arquivo de verdade (caminho absoluto, sem erros de digitação).
  2. Permissões. O usuário do servidor web precisa conseguir ler o arquivo. Verifique com sudo -u www-data cat /etc/nginx/.htpasswd.
  3. Quebras de linha / codificação. Um arquivo editado no Windows pode carregar caracteres \r que corrompem o hash. Rode file .htpasswd e aplique dos2unix se necessário.
  4. Cache velho do navegador. O navegador faz cache das credenciais por realm. Teste numa janela privada/anônima para descartar uma senha antiga lembrada.
  5. Hash incompatível. Verifique se o hash armazenado de fato corresponde à senha — cole os dois no modo de verificação do gerador de htpasswd para confirmar antes de culpar a configuração.

Quando NÃO usar o Basic Auth

O Basic Auth é a ferramenta certa para um conjunto restrito de tarefas: um site de staging, um caminho administrativo interno, um endpoint de artefatos de CI, um painel de métricas, um registry privado. É sem dependências e leva dois minutos para configurar.

É a ferramenta errada para o login de um produto. Não há logout, redefinição de senha, limitação de taxa, bloqueio de conta nem MFA. As credenciais são reenviadas a cada requisição e ficam em cache no navegador até ele fechar. Para qualquer coisa em que os usuários façam login, recorra a sessões, OAuth ou OIDC. Reconhecer esse limite é o que mantém o Basic Auth útil onde ele de fato se encaixa.

FAQ

O que uma única linha de um arquivo .htpasswd realmente contém?

Um par username:hash separado por dois-pontos. O hash começa com um prefixo de algoritmo ($2y$ para bcrypt, $apr1$ para o MD5 do Apache, {SHA} para SHA-1), seguido do salt e do digest. A senha em texto puro nunca aparece no arquivo.

Qual é a diferença entre .htpasswd e .htaccess?

O .htaccess é o arquivo de configuração por diretório do Apache — ele ativa o Basic Auth e aponta para o repositório de credenciais. O .htpasswd é esse repositório de credenciais, que guarda as linhas username:hash. O nginx usa o formato .htpasswd, mas configura a autenticação nos seus blocos server/location, não no .htaccess.

Como adiciono, altero ou removo um usuário em um arquivo .htpasswd?

Para adicionar ou alterar um usuário, rode htpasswd /path/.htpasswd username sem o -c — se o usuário existir, o hash dele é atualizado. Para remover um, rode htpasswd -D /path/.htpasswd username. Use o -c apenas para o primeiro usuário, já que ele sobrescreve o arquivo inteiro.

Como o navegador lembra as credenciais do Basic Auth, e como os usuários fazem logout?

O navegador faz cache das credenciais indexadas por realm e as reenvia automaticamente a cada requisição correspondente. Não há logout padrão: as únicas formas de limpá-las são fechar o navegador ou apagar o cache dele. Esse logout ausente é uma das razões pelas quais o Basic Auth não serve para autenticação de produto.

Posso usar o mesmo arquivo .htpasswd para Apache e nginx?

Sim, desde que o formato do hash seja suportado em ambos. O apr1 (MD5 do Apache) é verificado nativamente pelo Apache e pelo nginx em todo lugar, então é a escolha compartilhada mais segura. O bcrypt funciona no Apache, mas no nginx depende do crypt() do sistema, que falha em builds Alpine/musl.

A HTTP Basic Authentication ainda é relevante em 2026?

Sim. Como uma barreira leve em cima do HTTPS — ferramentas internas, ambientes de staging, registries privados, endpoints de monitoramento — ela continua prática e sem dependências. Só não a confunda com a autenticação de produto voltada ao usuário, que precisa de sessões, redefinições, limitação de taxa e MFA que o Basic Auth não consegue oferecer.

Revisado pela equipe Go Tools: cada comando, bloco de configuração e formato de hash deste guia foi verificado contra a saída de referência do Apache htpasswd (apache2-utils) e do OpenSSL.

Tags: htpasswd basic-auth http-authentication nginx apache bcrypt security

Artigos relacionados

Ver todos os artigos